1. Data Set Description For this project, our team decided to take a data-driven approach to evaluate music. We are using the Spotify Dataset from 1921 to 2020 that consists of over 160,000 different tracks. In order to stay consistent in the evaluation, all data was sourced from the Spotify Web API. The following set of data is combination of Primary, Numerical, Dummy(binary), and Categorical data. This allows us to explore different types of models and draw different insights. Here are all the variables that is included in the data set:

Primary - id: this an unique key comprised of numbers and characters that is assigned to each track generated by Spotify

Numerical - acousticness: range from 0(LOW) to 1(HIGH) - danceability: range from 0(LOW) to 1(HIGH) - energy: range from 0(LOW) to 1(HIGH) - duration_ms: majority range from 200,000 to 300,000 - instrumentalness: range from 0(LOW) to 1(HIGH) - valence: range from 0(LOW) to 1(HIGH) - popularity: range from 0(LOW) to 100(HIGH)* - tempo: majority range from 50(LOW) to 150(high) - liveness: range from 0(LOW) to 1(HIGH) - loudness majority range from -60 to 0 - speechiness: range from 0(LOW) to 1(HIGH) - year: range from 1921 to 2020

Dummy - mode: 0 represents minor and 1 represents major - explicit: 0 represents no explicit content and 1 represents explicit content

Categorical - key: this consists of all different music keys on onctave encoded from 0 to 11 (i.e. C = 0, C# = 1, etc…) - artists: the artist of the track - release_date: the date of release in yyyy-mm-dd format - name: the name of the track

*With our approach on evaluating different tracks, we decided to use popularity as our main dependant variable.

options(repr.matrix.max.rows=100, repr.matrix.max.cols=20)

Import all Libraries

# Libraries
options(warn=-1)
library(ggplot2)
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(plotly)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
library(hrbrthemes)
NOTE: Either Arial Narrow or Roboto Condensed fonts are required to use these themes.
      Please use hrbrthemes::import_roboto_condensed() to install Roboto Condensed and
      if Arial Narrow is not on your system, please see https://bit.ly/arialnarrow
library(forecast)
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
library(xts)
Loading required package: zoo

Attaching package: ‘zoo’

The following objects are masked from ‘package:base’:

    as.Date, as.Date.numeric


Attaching package: ‘xts’

The following objects are masked from ‘package:dplyr’:

    first, last
library(Metrics)

Attaching package: ‘Metrics’

The following object is masked from ‘package:forecast’:

    accuracy
library(psych)

Attaching package: ‘psych’

The following objects are masked from ‘package:ggplot2’:

    %+%, alpha
library(dygraphs)
library(GGally)
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ tibble  3.0.3     ✓ purrr   0.3.4
✓ tidyr   1.1.2     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.0
── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x psych::%+%()     masks ggplot2::%+%()
x psych::alpha()   masks ggplot2::alpha()
x plotly::filter() masks dplyr::filter(), stats::filter()
x xts::first()     masks dplyr::first()
x dplyr::lag()     masks stats::lag()
x xts::last()      masks dplyr::last()
library(tidyquant)  
Loading required package: lubridate

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union

Loading required package: PerformanceAnalytics

Attaching package: ‘PerformanceAnalytics’

The following object is masked from ‘package:graphics’:

    legend

Loading required package: quantmod
Loading required package: TTR
Version 0.4-0 included new data defaults. See ?getSymbols.
══ Need to Learn tidyquant? ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════
Business Science offers a 1-hour course - Learning Lab #9: Performance Analysis & Portfolio Optimization with tidyquant!
</> Learn more at: https://university.business-science.io/p/learning-labs-pro </>
library(cranlogs)   
library(corrr)      
library(cowplot)  

Attaching package: ‘cowplot’

The following object is masked from ‘package:lubridate’:

    stamp
library(Metrics)

Initial data visualization

Plotting annual median values for each feature overall. Standardized such that each feature is on the same scale.

df <- read.csv("./data/data.csv")
q1s = data.frame(matrix(ncol=3, nrow=0))
medians = data.frame(matrix(ncol=3, nrow=0))
q3s = data.frame(matrix(ncol=3, nrow=0))
feature_names = sort(c("acousticness", "danceability", "instrumentalness", "energy",
                  "duration_ms", "valence", "tempo", "liveness", "loudness", "speechiness"))
for(i in 1921:2020){
  annual_val = subset(df, year==i)

  for(name in feature_names){
    vals = quantile(annual_val[,name])[2:4]
    q1s <- rbind(q1s, c(i, name, vals[1]))
    medians <- rbind(medians, c(i, name, vals[2]))
    q3s <- rbind(q3s, c(i, name, vals[3]))
  }
}

colnames(q1s) <-c("Year", "Feature", "Value")
colnames(medians) <-c("Year", "Feature", "Value")
colnames(q3s) <-c("Year", "Feature", "Value")

split_q1s <- split(q1s, q1s$Feature)
split_medians <- split(medians, medians$Feature)
split_q3s <- split(q3s, q3s$Feature)

feature_quantiles = array(0, c(100,3,length(feature_names)))

for(i in 1:length(feature_names)){
  for(j in 1:100){
    feature_quantiles[j,1,i] = split_q1s[[i]][[3]][j]
    feature_quantiles[j,2,i] = split_medians[[i]][[3]][j]
    feature_quantiles[j,3,i] = split_q3s[[i]][[3]][j]
  }
}

dimnames(feature_quantiles) <- list(1921:2020,
                                    c("Q1", "Median", "Q3"),
                                    feature_names)



plot(1930,1, xlim = c(1921,2020), ylim = range(0,15), xlab="Year", ylab="Range")
for(i in 1:length(feature_names)){
  name = feature_names[i]
  medians = as.numeric(feature_quantiles[,,name][,"Median"])

  avg = mean(medians)
  medians = medians / avg
  
  lines(x=1921:2020, y=medians, col=i)
}
legend("topright", lty=1, col=c(1,2,3,4,5,6,7,8,9,10), legend=feature_names)

Plotting annual median values for the feature for the top 10% of songs by popularity. Standardized such that each feature is on the same scale.

q1s = data.frame(matrix(ncol=3, nrow=0))
medians = data.frame(matrix(ncol=3, nrow=0))
q3s = data.frame(matrix(ncol=3, nrow=0))
feature_names = sort(c("acousticness", "danceability", "instrumentalness", "energy",
                  "duration_ms", "valence", "tempo", "liveness", "loudness", "speechiness"))
for(i in 1921:2020){
  annual_val = subset(df, year==i)
  
  
  top_10 = floor(nrow(annual_val)*0.1)
  annual_val = annual_val[order(annual_val$popularity, decreasing=TRUE),]
  annual_val = annual_val[1:top_10,]

  for(name in feature_names){
    vals = quantile(annual_val[,name])[2:4]
    q1s <- rbind(q1s, c(i, name, vals[1]))
    medians <- rbind(medians, c(i, name, vals[2]))
    q3s <- rbind(q3s, c(i, name, vals[3]))
  }
}

colnames(q1s) <-c("Year", "Feature", "Value")
colnames(medians) <-c("Year", "Feature", "Value")
colnames(q3s) <-c("Year", "Feature", "Value")

split_q1s <- split(q1s, q1s$Feature)
split_medians <- split(medians, medians$Feature)
split_q3s <- split(q3s, q3s$Feature)

feature_quantiles = array(0, c(100,3,length(feature_names)))

for(i in 1:length(feature_names)){
  for(j in 1:100){
    feature_quantiles[j,1,i] = split_q1s[[i]][[3]][j]
    feature_quantiles[j,2,i] = split_medians[[i]][[3]][j]
    feature_quantiles[j,3,i] = split_q3s[[i]][[3]][j]
  }
}

dimnames(feature_quantiles) <- list(1921:2020,
                                    c("Q1", "Median", "Q3"),
                                    feature_names)


plot(1930,1, xlim = c(1921,2020), ylim = range(0,17), xlab="Year", ylab="Range")
for(i in 1:length(feature_names)){
  name = feature_names[i]
  medians = as.numeric(feature_quantiles[,,name][,"Median"])
  avg = mean(medians)
  medians = medians / avg
  
  lines(x=1921:2020, y=medians, col=i)
}
legend("topright", lty=1, col=c(1,2,3,4,5,6,7,8,9,10), legend=feature_names)

####Insights:
Both these graphs appear to have similar shapes, with instrumentalness being the most widely varying, and the rest varying marginally. However, for the speechiness variable, for the overall set of songs its median value varies much less than the median value for the most popular songs.

Train time series models to forecast the future models.

# Set up the libraries and the training/testing amounts
library("smooth")
Loading required package: greybox
Package "greybox", v0.6.3 loaded.


Attaching package: ‘greybox’

The following object is masked from ‘package:lubridate’:

    hm

The following object is masked from ‘package:tidyr’:

    spread

This is package "smooth", v2.6.0

Attaching package: ‘smooth’

The following object is masked from ‘package:TTR’:

    lags
library("forecast")
library("nnfor")
training.percent = 0.95
nTrain = 100*training.percent
nTest = 100*(1-training.percent)

Accousticness Models

acousticness = ts(as.numeric(feature_quantiles[,"acousticness"]) , start=1921)
acousticness.train = subset(acousticness, start=1, end=nTrain)
acousticness.test = subset(acousticness, start = (nTrain+1), end =(nTrain+nTest))

#ses
acousticness.train.ses <- ses(acousticness.train, h=nTest)
acousticness.ses.mape = mape(acousticness.train.ses$mean, acousticness.test)
plot(acousticness.train.ses, main=paste("Acousticness", "SES"), sub=paste("MAPE:", round(acousticness.ses.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(acousticness)


#SARIMA
acousticness.sarima.model <- auto.arima(acousticness.train)
acousticness.sarima <- forecast(acousticness.sarima.model, h=nTest)
acousticness.sarima.mape = mape(acousticness.sarima$mean, acousticness.test)
plot(acousticness.sarima, main=paste("Acousticness", "SARIMA"), sub=paste("MAPE:", round(acousticness.sarima.mape*100,3), "%"), xlab="Year", ylab="Median Value")
lines(acousticness)


#Neural Network
acousticness.train.nn <- elm(acousticness.train)
acousticness.nn.forecast <- forecast(acousticness.train.nn, h=nTest)
acousticness.nn.mape = mape(acousticness.nn.forecast$mean, acousticness.test)
plot(acousticness, main=paste("Acousticness", "NN"), sub=paste("MAPE:", round(acousticness.nn.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(ts(acousticness.nn.forecast$mean, start=1921+nTrain), col=2)

Here we see that the best method to predict future acousticness median values for the overall data set is through SES. However, given that this best MAPE is roughly 37%, this feature cannot be reliably forecast into the future.

Energy models

energy = ts(as.numeric(feature_quantiles[,"energy"]) , start=1921)
energy.train = subset(energy, start=1, end=nTrain)
energy.test = subset(energy, start = (nTrain+1), end =(nTrain+nTest))

#SES
energy.train.ses <- ses(energy.train, h=nTest)
energy.ses.mape = mape(energy.train.ses$mean, energy.test)
plot(energy.train.ses, main=paste("Energy", "SES"), sub=paste("MAPE:", round(energy.ses.mape* 100, 3), "%"), xlab="Year", ylab="Median Value")
lines(energy)


#SARIMA
energy.sarima.model <- auto.arima(energy.train)
energy.sarima <- forecast(energy.sarima.model, h=nTest)
energy.sarima.mape = mape(energy.sarima$mean, energy.test)
plot(energy.sarima, main=paste("Energy", "SARIMA"), sub=paste("MAPE:", round(energy.sarima.mape* 100, 3), "%"), xlab="Year", ylab="Median Value")
lines(energy)


#Neural Network
energy.train.nn <- elm(energy.train)
energy.nn.forecast <- forecast(energy.train.nn, h=nTest)
energy.nn.mape = mape(energy.nn.forecast$mean, energy.test)
plot(energy, main=paste("Energy", "NN"), sub=paste("MAPE:", round(energy.nn.mape* 100, 3), "%"), xlab="Year", ylab="Median Value")
lines(ts(energy.nn.forecast$mean, start=1921+nTrain), col=2)

Here we see that the best method to predict future energy median values for the overall data set is through SES. Given that this best MAPE is roughly 8%, this feature can be fairly reliably forecast into the future.

Danceability models

danceability = ts(as.numeric(feature_quantiles[,"danceability"]) , start=1921)
danceability.train = subset(danceability, start=1, end=nTrain)
danceability.test = subset(danceability, start = (nTrain+1), end =(nTrain+nTest))

#SES
danceability.train.ses <- ses(danceability.train, h=nTest)
danceability.ses.mape = mape(danceability.train.ses$mean, danceability.test)
plot(danceability.train.ses, main=paste("danceability", "SES"), sub=paste("MAPE:", round(danceability.ses.mape* 100, 3), "%"), xlab="Year", ylab="Median Value")
lines(danceability)


#SARIMA
danceability.sarima.model <- auto.arima(danceability.train)
danceability.sarima <- forecast(danceability.sarima.model, h=nTest)
danceability.sarima.mape = mape(danceability.sarima$mean, danceability.test)
plot(danceability.sarima, main=paste("danceability", "SARIMA"), sub=paste("MAPE:", round(danceability.sarima.mape* 100, 3), "%"), xlab="Year", ylab="Median Value")
lines(danceability)


#Neural Network
danceability.train.nn <- elm(danceability.train)
danceability.nn.forecast <- forecast(danceability.train.nn, h=nTest)
danceability.nn.mape = mape(danceability.nn.forecast$mean, danceability.test)
plot(danceability, main=paste("danceability", "NN"), sub=paste("MAPE:", round(danceability.nn.mape* 100, 3), "%"), xlab="Year", ylab="Median Value")
lines(ts(danceability.nn.forecast$mean, start=1921+nTrain), col=2)

Here we see that the best method to predict future danceability median values for the overall data set is through NN. However, given that this best MAPE is roughly 10.4%, this feature cannot be reliably forecast into the future.

Duration models

duration = ts(as.numeric(feature_quantiles[,"duration_ms"]) , start=1921)
duration.train = subset(duration, start=1, end=nTrain)
duration.test = subset(duration, start = (nTrain+1), end =(nTrain+nTest))

#SES
duration.train.ses <- ses(duration.train, h=nTest)
duration.ses.mape = mape(duration.train.ses$mean, duration.test)
plot(duration.train.ses, main=paste("Duration", "SES"), sub=paste("MAPE:",round(duration.ses.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(duration)


#SARIMA
duration.sarima.model <- auto.arima(duration.train)
duration.sarima <- forecast(duration.sarima.model, h=nTest)
duration.sarima.mape = mape(duration.sarima$mean, duration.test)
plot(duration.sarima, main=paste("Duration", "SARIMA"), sub=paste("MAPE:", round(duration.sarima.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(duration)



#Neural Network
duration.train.nn <- elm(duration.train)
duration.nn.forecast <- forecast(duration.train.nn, h=nTest)
duration.nn.mape = mape(duration.nn.forecast$mean, duration.test)
plot(duration, main=paste("Duration", "NN"), sub=paste("MAPE:", round(duration.nn.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(ts(duration.nn.forecast$mean, start=1921+nTrain), col=2)

Here we see that the best method to predict future duration median values for the overall data set is through NN. Given that this best MAPE is roughly 8%, this feature can be fairly reliably forecast into the future.

Valence

valence = ts(as.numeric(feature_quantiles[,"valence"]) , start=1921)
valence.train = subset(valence, start=1, end=nTrain)
valence.test = subset(valence, start = (nTrain+1), end =(nTrain+nTest))

#SES
valence.train.ses <- ses(valence.train, h=nTest)
valence.ses.mape = mape(valence.train.ses$mean, valence.test)
plot(valence.train.ses, main=paste("valence", "SES"), sub=paste("MAPE:",round(valence.ses.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(valence)


#SARIMA
valence.sarima.model <- auto.arima(valence.train)
valence.sarima <- forecast(valence.sarima.model, h=nTest)
valence.sarima.mape = mape(valence.sarima$mean, valence.test)
plot(valence.sarima, main=paste("valence", "SARIMA"), sub=paste("MAPE:", round(valence.sarima.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(valence)



#Neural Network
valence.train.nn <- elm(valence.train)
valence.nn.forecast <- forecast(valence.train.nn, h=nTest)
valence.nn.mape = mape(valence.nn.forecast$mean, valence.test)
plot(valence, main=paste("valence", "NN"), sub=paste("MAPE:", round(valence.nn.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(ts(valence.nn.forecast$mean, start=1921+nTrain), col=2)

Insights:

Relatively lower MAPE indicates that we can predict valence over time. The best model to use is the SARIMA model because it has the lowest MAPE at 6.7%.

Tempo model

tempo = ts(as.numeric(feature_quantiles[,"tempo"]) , start=1921)
tempo.train = subset(tempo, start=1, end=nTrain)
tempo.test = subset(tempo, start = (nTrain+1), end =(nTrain+nTest))

#SES
tempo.train.ses <- ses(tempo.train, h=nTest)
tempo.ses.mape = mape(tempo.train.ses$mean, tempo.test)
plot(tempo.train.ses, main=paste("tempo", "SES"), sub=paste("MAPE:",round(tempo.ses.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(tempo)


#SARIMA
tempo.sarima.model <- auto.arima(tempo.train)
tempo.sarima <- forecast(tempo.sarima.model, h=nTest)
tempo.sarima.mape = mape(tempo.sarima$mean, tempo.test)
plot(tempo.sarima, main=paste("tempo", "SARIMA"), sub=paste("MAPE:", round(tempo.sarima.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(tempo)



#Neural Network
tempo.train.nn <- elm(tempo.train)
tempo.nn.forecast <- forecast(tempo.train.nn, h=nTest)
tempo.nn.mape = mape(tempo.nn.forecast$mean, tempo.test)
plot(tempo, main=paste("tempo", "NN"), sub=paste("MAPE:", round(tempo.nn.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(ts(tempo.nn.forecast$mean, start=1921+nTrain), col=2)

Insights:

Here we see that the best method to predict future tempo median values for the overall data set is through SES. Given that this best MAPE is roughly 1%, this feature can be fairly reliably forecast into the future.

Liveness

liveness = ts(as.numeric(feature_quantiles[,"liveness"]) , start=1921)
liveness.train = subset(liveness, start=1, end=nTrain)
liveness.test = subset(liveness, start = (nTrain+1), end =(nTrain+nTest))

#SES
liveness.train.ses <- ses(liveness.train, h=nTest)
liveness.ses.mape = mape(liveness.train.ses$mean, liveness.test)
plot(liveness.train.ses, main=paste("liveness", "SES"), sub=paste("MAPE:",round(liveness.ses.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(liveness)


#SARIMA
liveness.sarima.model <- auto.arima(liveness.train)
liveness.sarima <- forecast(liveness.sarima.model, h=nTest)
liveness.sarima.mape = mape(liveness.sarima$mean, liveness.test)
plot(liveness.sarima, main=paste("liveness", "SARIMA"), sub=paste("MAPE:", round(liveness.sarima.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(liveness)



#Neural Network
liveness.train.nn <- elm(liveness.train)
liveness.nn.forecast <- forecast(liveness.train.nn, h=nTest)
liveness.nn.mape = mape(liveness.nn.forecast$mean, liveness.test)
plot(liveness, main=paste("liveness", "NN"), sub=paste("MAPE:", round(liveness.nn.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(ts(liveness.nn.forecast$mean, start=1921+nTrain), col=2)

Insights:

Here we see that the best method to predict future liveness median values for the overall data set is through SARIMA Given that this best MAPE is roughly 2.6%, this feature can be fairly reliably forecast into the future.

Loudness

loudness = ts(as.numeric(feature_quantiles[,"loudness"]) , start=1921)
loudness.train = subset(loudness, start=1, end=nTrain)
loudness.test = subset(loudness, start = (nTrain+1), end =(nTrain+nTest))

#SES
loudness.train.ses <- ses(loudness.train, h=nTest)
loudness.ses.mape = mape(loudness.train.ses$mean, loudness.test)
plot(loudness.train.ses, main=paste("loudness", "SES"), sub=paste("MAPE:",round(loudness.ses.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(loudness)


#SARIMA
loudness.sarima.model <- auto.arima(loudness.train)
loudness.sarima <- forecast(loudness.sarima.model, h=nTest)
loudness.sarima.mape = mape(loudness.sarima$mean, loudness.test)
plot(loudness.sarima, main=paste("loudness", "SARIMA"), sub=paste("MAPE:", round(loudness.sarima.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(loudness)



#Neural Network
loudness.train.nn <- elm(loudness.train)
loudness.nn.forecast <- forecast(loudness.train.nn, h=nTest)
loudness.nn.mape = mape(loudness.nn.forecast$mean, loudness.test)
plot(loudness, main=paste("loudness", "NN"), sub=paste("MAPE:", round(loudness.nn.mape*100, 3), "%"), xlab="Year", ylab="Median Value")
lines(ts(loudness.nn.forecast$mean, start=1921+nTrain), col=2)

Insights:

Here we see that the best method to predict future loudness median values for the overall data set is through SES Given that this best MAPE is roughly 5%, this feature can be fairly reliably forecast into the future.

LS0tCnRpdGxlOiAiU3BvdGlmeSBEYXRhIEFuYWx5c2lzIGFuZCBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiBDUyBEdWFscwpkYXRlOiBOb3ZlbWJlciAxOCwgMjAyMAotLS0KCjEuIERhdGEgU2V0IERlc2NyaXB0aW9uCkZvciB0aGlzIHByb2plY3QsIG91ciB0ZWFtIGRlY2lkZWQgdG8gdGFrZSBhIGRhdGEtZHJpdmVuIGFwcHJvYWNoIHRvIGV2YWx1YXRlIG11c2ljLiBXZSBhcmUgdXNpbmcgdGhlIFNwb3RpZnkgRGF0YXNldCBmcm9tIDE5MjEgdG8gMjAyMCB0aGF0IGNvbnNpc3RzIG9mIG92ZXIgMTYwLDAwMCBkaWZmZXJlbnQgdHJhY2tzLiBJbiBvcmRlciB0byBzdGF5IGNvbnNpc3RlbnQgaW4gdGhlIGV2YWx1YXRpb24sIGFsbCBkYXRhIHdhcyBzb3VyY2VkIGZyb20gdGhlIFNwb3RpZnkgV2ViIEFQSS4gVGhlIGZvbGxvd2luZyBzZXQgb2YgZGF0YSBpcyBjb21iaW5hdGlvbiBvZiBQcmltYXJ5LCBOdW1lcmljYWwsIER1bW15KGJpbmFyeSksIGFuZCBDYXRlZ29yaWNhbCBkYXRhLiBUaGlzIGFsbG93cyB1cyB0byBleHBsb3JlIGRpZmZlcmVudCB0eXBlcyBvZiBtb2RlbHMgYW5kIGRyYXcgZGlmZmVyZW50IGluc2lnaHRzLiBIZXJlIGFyZSBhbGwgdGhlIHZhcmlhYmxlcyB0aGF0IGlzIGluY2x1ZGVkIGluIHRoZSBkYXRhIHNldDoKClByaW1hcnkKICAgIC0gaWQ6IHRoaXMgYW4gdW5pcXVlIGtleSBjb21wcmlzZWQgb2YgbnVtYmVycyBhbmQgY2hhcmFjdGVycyB0aGF0IGlzIGFzc2lnbmVkIHRvIGVhY2ggdHJhY2sgZ2VuZXJhdGVkIGJ5IFNwb3RpZnkKCk51bWVyaWNhbAogICAgLSBhY291c3RpY25lc3M6IHJhbmdlIGZyb20gMChMT1cpIHRvIDEoSElHSCkKICAgIC0gZGFuY2VhYmlsaXR5OiByYW5nZSBmcm9tIDAoTE9XKSB0byAxKEhJR0gpCiAgICAtIGVuZXJneTogcmFuZ2UgZnJvbSAwKExPVykgdG8gMShISUdIKQogICAgLSBkdXJhdGlvbl9tczogbWFqb3JpdHkgcmFuZ2UgZnJvbSAyMDAsMDAwIHRvIDMwMCwwMDAKICAgIC0gaW5zdHJ1bWVudGFsbmVzczogcmFuZ2UgZnJvbSAwKExPVykgdG8gMShISUdIKQogICAgLSB2YWxlbmNlOiByYW5nZSBmcm9tIDAoTE9XKSB0byAxKEhJR0gpCiAgICAtIHBvcHVsYXJpdHk6IHJhbmdlIGZyb20gMChMT1cpIHRvIDEwMChISUdIKSoKICAgIC0gdGVtcG86IG1ham9yaXR5IHJhbmdlIGZyb20gNTAoTE9XKSB0byAxNTAoaGlnaCkKICAgIC0gbGl2ZW5lc3M6IHJhbmdlIGZyb20gMChMT1cpIHRvIDEoSElHSCkKICAgIC0gbG91ZG5lc3MgbWFqb3JpdHkgcmFuZ2UgZnJvbSAtNjAgdG8gMAogICAgLSBzcGVlY2hpbmVzczogcmFuZ2UgZnJvbSAwKExPVykgdG8gMShISUdIKQogICAgLSB5ZWFyOiByYW5nZSBmcm9tIDE5MjEgdG8gMjAyMAoKRHVtbXkKICAgIC0gbW9kZTogMCByZXByZXNlbnRzIG1pbm9yIGFuZCAxIHJlcHJlc2VudHMgbWFqb3IKICAgIC0gZXhwbGljaXQ6IDAgcmVwcmVzZW50cyBubyBleHBsaWNpdCBjb250ZW50IGFuZCAxIHJlcHJlc2VudHMgZXhwbGljaXQgY29udGVudAogICAgCkNhdGVnb3JpY2FsCiAgICAtIGtleTogdGhpcyBjb25zaXN0cyBvZiBhbGwgZGlmZmVyZW50IG11c2ljIGtleXMgb24gb25jdGF2ZSBlbmNvZGVkIGZyb20gMCB0byAxMSAoaS5lLiBDID0gMCwgQyMgPSAxLCBldGMuLi4pCiAgICAtIGFydGlzdHM6IHRoZSBhcnRpc3Qgb2YgdGhlIHRyYWNrCiAgICAtIHJlbGVhc2VfZGF0ZTogdGhlIGRhdGUgb2YgcmVsZWFzZSBpbiB5eXl5LW1tLWRkIGZvcm1hdAogICAgLSBuYW1lOiB0aGUgbmFtZSBvZiB0aGUgdHJhY2sKCipXaXRoIG91ciBhcHByb2FjaCBvbiBldmFsdWF0aW5nIGRpZmZlcmVudCB0cmFja3MsIHdlIGRlY2lkZWQgdG8gdXNlIHBvcHVsYXJpdHkgYXMgb3VyIG1haW4gZGVwZW5kYW50IHZhcmlhYmxlLiAKCgpgYGB7cn0Kb3B0aW9ucyhyZXByLm1hdHJpeC5tYXgucm93cz0xMDAsIHJlcHIubWF0cml4Lm1heC5jb2xzPTIwKQpgYGAKCgpJbXBvcnQgYWxsIExpYnJhcmllcwpgYGB7cn0KIyBMaWJyYXJpZXMKb3B0aW9ucyh3YXJuPS0xKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGhyYnJ0aGVtZXMpCmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkoeHRzKQpsaWJyYXJ5KE1ldHJpY3MpCmxpYnJhcnkocHN5Y2gpCmxpYnJhcnkoZHlncmFwaHMpCmxpYnJhcnkoR0dhbGx5KQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh0aWR5cXVhbnQpICAKbGlicmFyeShjcmFubG9ncykgICAKbGlicmFyeShjb3JycikgICAgICAKbGlicmFyeShjb3dwbG90KSAgCmxpYnJhcnkoTWV0cmljcykKYGBgCiMgSW5pdGlhbCBkYXRhIHZpc3VhbGl6YXRpb24KIyMgUGxvdHRpbmcgYW5udWFsIG1lZGlhbiB2YWx1ZXMgZm9yIGVhY2ggZmVhdHVyZSBvdmVyYWxsLiBTdGFuZGFyZGl6ZWQgc3VjaCB0aGF0IGVhY2ggZmVhdHVyZSBpcyBvbiB0aGUgc2FtZSBzY2FsZS4KYGBge3J9CmRmIDwtIHJlYWQuY3N2KCIuL2RhdGEvZGF0YS5jc3YiKQpxMXMgPSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPTMsIG5yb3c9MCkpCm1lZGlhbnMgPSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPTMsIG5yb3c9MCkpCnEzcyA9IGRhdGEuZnJhbWUobWF0cml4KG5jb2w9MywgbnJvdz0wKSkKZmVhdHVyZV9uYW1lcyA9IHNvcnQoYygiYWNvdXN0aWNuZXNzIiwgImRhbmNlYWJpbGl0eSIsICJpbnN0cnVtZW50YWxuZXNzIiwgImVuZXJneSIsCiAgICAgICAgICAgICAgICAgICJkdXJhdGlvbl9tcyIsICJ2YWxlbmNlIiwgInRlbXBvIiwgImxpdmVuZXNzIiwgImxvdWRuZXNzIiwgInNwZWVjaGluZXNzIikpCmZvcihpIGluIDE5MjE6MjAyMCl7CiAgYW5udWFsX3ZhbCA9IHN1YnNldChkZiwgeWVhcj09aSkKCiAgZm9yKG5hbWUgaW4gZmVhdHVyZV9uYW1lcyl7CiAgICB2YWxzID0gcXVhbnRpbGUoYW5udWFsX3ZhbFssbmFtZV0pWzI6NF0KICAgIHExcyA8LSByYmluZChxMXMsIGMoaSwgbmFtZSwgdmFsc1sxXSkpCiAgICBtZWRpYW5zIDwtIHJiaW5kKG1lZGlhbnMsIGMoaSwgbmFtZSwgdmFsc1syXSkpCiAgICBxM3MgPC0gcmJpbmQocTNzLCBjKGksIG5hbWUsIHZhbHNbM10pKQogIH0KfQoKY29sbmFtZXMocTFzKSA8LWMoIlllYXIiLCAiRmVhdHVyZSIsICJWYWx1ZSIpCmNvbG5hbWVzKG1lZGlhbnMpIDwtYygiWWVhciIsICJGZWF0dXJlIiwgIlZhbHVlIikKY29sbmFtZXMocTNzKSA8LWMoIlllYXIiLCAiRmVhdHVyZSIsICJWYWx1ZSIpCgpzcGxpdF9xMXMgPC0gc3BsaXQocTFzLCBxMXMkRmVhdHVyZSkKc3BsaXRfbWVkaWFucyA8LSBzcGxpdChtZWRpYW5zLCBtZWRpYW5zJEZlYXR1cmUpCnNwbGl0X3EzcyA8LSBzcGxpdChxM3MsIHEzcyRGZWF0dXJlKQoKZmVhdHVyZV9xdWFudGlsZXMgPSBhcnJheSgwLCBjKDEwMCwzLGxlbmd0aChmZWF0dXJlX25hbWVzKSkpCgpmb3IoaSBpbiAxOmxlbmd0aChmZWF0dXJlX25hbWVzKSl7CiAgZm9yKGogaW4gMToxMDApewogICAgZmVhdHVyZV9xdWFudGlsZXNbaiwxLGldID0gc3BsaXRfcTFzW1tpXV1bWzNdXVtqXQogICAgZmVhdHVyZV9xdWFudGlsZXNbaiwyLGldID0gc3BsaXRfbWVkaWFuc1tbaV1dW1szXV1bal0KICAgIGZlYXR1cmVfcXVhbnRpbGVzW2osMyxpXSA9IHNwbGl0X3Ezc1tbaV1dW1szXV1bal0KICB9Cn0KCmRpbW5hbWVzKGZlYXR1cmVfcXVhbnRpbGVzKSA8LSBsaXN0KDE5MjE6MjAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiUTEiLCAiTWVkaWFuIiwgIlEzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVfbmFtZXMpCgoKCnBsb3QoMTkzMCwxLCB4bGltID0gYygxOTIxLDIwMjApLCB5bGltID0gcmFuZ2UoMCwxNSksIHhsYWI9IlllYXIiLCB5bGFiPSJSYW5nZSIpCmZvcihpIGluIDE6bGVuZ3RoKGZlYXR1cmVfbmFtZXMpKXsKICBuYW1lID0gZmVhdHVyZV9uYW1lc1tpXQogIG1lZGlhbnMgPSBhcy5udW1lcmljKGZlYXR1cmVfcXVhbnRpbGVzWywsbmFtZV1bLCJNZWRpYW4iXSkKCiAgYXZnID0gbWVhbihtZWRpYW5zKQogIG1lZGlhbnMgPSBtZWRpYW5zIC8gYXZnCiAgCiAgbGluZXMoeD0xOTIxOjIwMjAsIHk9bWVkaWFucywgY29sPWkpCn0KbGVnZW5kKCJ0b3ByaWdodCIsIGx0eT0xLCBjb2w9YygxLDIsMyw0LDUsNiw3LDgsOSwxMCksIGxlZ2VuZD1mZWF0dXJlX25hbWVzKQpgYGAKCgojIyBQbG90dGluZyBhbm51YWwgbWVkaWFuIHZhbHVlcyBmb3IgdGhlIGZlYXR1cmUgZm9yIHRoZSAqdG9wIDEwJSBvZiBzb25ncyogYnkgcG9wdWxhcml0eS4gU3RhbmRhcmRpemVkIHN1Y2ggdGhhdCBlYWNoIGZlYXR1cmUgaXMgb24gdGhlIHNhbWUgc2NhbGUuCmBgYHtyfQpxMXMgPSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPTMsIG5yb3c9MCkpCm1lZGlhbnMgPSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPTMsIG5yb3c9MCkpCnEzcyA9IGRhdGEuZnJhbWUobWF0cml4KG5jb2w9MywgbnJvdz0wKSkKZmVhdHVyZV9uYW1lcyA9IHNvcnQoYygiYWNvdXN0aWNuZXNzIiwgImRhbmNlYWJpbGl0eSIsICJpbnN0cnVtZW50YWxuZXNzIiwgImVuZXJneSIsCiAgICAgICAgICAgICAgICAgICJkdXJhdGlvbl9tcyIsICJ2YWxlbmNlIiwgInRlbXBvIiwgImxpdmVuZXNzIiwgImxvdWRuZXNzIiwgInNwZWVjaGluZXNzIikpCmZvcihpIGluIDE5MjE6MjAyMCl7CiAgYW5udWFsX3ZhbCA9IHN1YnNldChkZiwgeWVhcj09aSkKICAKICAKICB0b3BfMTAgPSBmbG9vcihucm93KGFubnVhbF92YWwpKjAuMSkKICBhbm51YWxfdmFsID0gYW5udWFsX3ZhbFtvcmRlcihhbm51YWxfdmFsJHBvcHVsYXJpdHksIGRlY3JlYXNpbmc9VFJVRSksXQogIGFubnVhbF92YWwgPSBhbm51YWxfdmFsWzE6dG9wXzEwLF0KCiAgZm9yKG5hbWUgaW4gZmVhdHVyZV9uYW1lcyl7CiAgICB2YWxzID0gcXVhbnRpbGUoYW5udWFsX3ZhbFssbmFtZV0pWzI6NF0KICAgIHExcyA8LSByYmluZChxMXMsIGMoaSwgbmFtZSwgdmFsc1sxXSkpCiAgICBtZWRpYW5zIDwtIHJiaW5kKG1lZGlhbnMsIGMoaSwgbmFtZSwgdmFsc1syXSkpCiAgICBxM3MgPC0gcmJpbmQocTNzLCBjKGksIG5hbWUsIHZhbHNbM10pKQogIH0KfQoKY29sbmFtZXMocTFzKSA8LWMoIlllYXIiLCAiRmVhdHVyZSIsICJWYWx1ZSIpCmNvbG5hbWVzKG1lZGlhbnMpIDwtYygiWWVhciIsICJGZWF0dXJlIiwgIlZhbHVlIikKY29sbmFtZXMocTNzKSA8LWMoIlllYXIiLCAiRmVhdHVyZSIsICJWYWx1ZSIpCgpzcGxpdF9xMXMgPC0gc3BsaXQocTFzLCBxMXMkRmVhdHVyZSkKc3BsaXRfbWVkaWFucyA8LSBzcGxpdChtZWRpYW5zLCBtZWRpYW5zJEZlYXR1cmUpCnNwbGl0X3EzcyA8LSBzcGxpdChxM3MsIHEzcyRGZWF0dXJlKQoKZmVhdHVyZV9xdWFudGlsZXMgPSBhcnJheSgwLCBjKDEwMCwzLGxlbmd0aChmZWF0dXJlX25hbWVzKSkpCgpmb3IoaSBpbiAxOmxlbmd0aChmZWF0dXJlX25hbWVzKSl7CiAgZm9yKGogaW4gMToxMDApewogICAgZmVhdHVyZV9xdWFudGlsZXNbaiwxLGldID0gc3BsaXRfcTFzW1tpXV1bWzNdXVtqXQogICAgZmVhdHVyZV9xdWFudGlsZXNbaiwyLGldID0gc3BsaXRfbWVkaWFuc1tbaV1dW1szXV1bal0KICAgIGZlYXR1cmVfcXVhbnRpbGVzW2osMyxpXSA9IHNwbGl0X3Ezc1tbaV1dW1szXV1bal0KICB9Cn0KCmRpbW5hbWVzKGZlYXR1cmVfcXVhbnRpbGVzKSA8LSBsaXN0KDE5MjE6MjAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiUTEiLCAiTWVkaWFuIiwgIlEzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVfbmFtZXMpCgoKcGxvdCgxOTMwLDEsIHhsaW0gPSBjKDE5MjEsMjAyMCksIHlsaW0gPSByYW5nZSgwLDE3KSwgeGxhYj0iWWVhciIsIHlsYWI9IlJhbmdlIikKZm9yKGkgaW4gMTpsZW5ndGgoZmVhdHVyZV9uYW1lcykpewogIG5hbWUgPSBmZWF0dXJlX25hbWVzW2ldCiAgbWVkaWFucyA9IGFzLm51bWVyaWMoZmVhdHVyZV9xdWFudGlsZXNbLCxuYW1lXVssIk1lZGlhbiJdKQogIGF2ZyA9IG1lYW4obWVkaWFucykKICBtZWRpYW5zID0gbWVkaWFucyAvIGF2ZwogIAogIGxpbmVzKHg9MTkyMToyMDIwLCB5PW1lZGlhbnMsIGNvbD1pKQp9CmxlZ2VuZCgidG9wcmlnaHQiLCBsdHk9MSwgY29sPWMoMSwyLDMsNCw1LDYsNyw4LDksMTApLCBsZWdlbmQ9ZmVhdHVyZV9uYW1lcykKYGBgCiMjIyNJbnNpZ2h0czogIApCb3RoIHRoZXNlIGdyYXBocyBhcHBlYXIgdG8gaGF2ZSBzaW1pbGFyIHNoYXBlcywgd2l0aCBpbnN0cnVtZW50YWxuZXNzIGJlaW5nIHRoZSBtb3N0IHdpZGVseSB2YXJ5aW5nLCBhbmQgdGhlIHJlc3QgdmFyeWluZyBtYXJnaW5hbGx5LiBIb3dldmVyLCBmb3IgdGhlIHNwZWVjaGluZXNzIHZhcmlhYmxlLCBmb3IgdGhlIG92ZXJhbGwgc2V0IG9mIHNvbmdzIGl0cyBtZWRpYW4gdmFsdWUgdmFyaWVzIG11Y2ggbGVzcyB0aGFuIHRoZSBtZWRpYW4gdmFsdWUgZm9yIHRoZSBtb3N0IHBvcHVsYXIgc29uZ3MuCgoKCiMjIE5vdyBwbG90dGluZyBhYnNvbHV0ZSB2YWx1ZXMgZm9yIGVhY2ggZmVhdHVyZSBhcyB0aGUgbWVkaWFuIHZhbHVlcyBmb3Igb3ZlcmFsbCwgYXMgd2VsbCBhcyBqdXN0IHRoZSBtb3N0IHBvcHVsYXIgc29uZ3MuCiMjIyBNQVBFIGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG1vc3QgcG9wdWxhciBtZWRpYW4gYW5kIHRoZSBvdmVyYWxsIG1lZGlhbjsgUiBpcyB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiBvdmVyYWxsIG1lZGlhbiBhbmQgbW9zdCBwb3B1bGFyIG1lZGlhbi4KIyMjIFRoZXNlIHZhbHVlcyB3aWxsIGRldGVybWluZSB3aGV0aGVyIG9yIG5vdCB0aGUgb3ZlcmFsbCBtZWRpYW4gaXMgYSB1c2VmdWwgcHJlZGljdG9yIG9mIHdoYXQgdGhlIG1lZGlhbiBmb3IgcG9wdWxhciBzb25ncyB3aWxsIGJlLiBUaGlzIGlzIGltcG9ydGFudCBiZWNhdXNlIGl0IHdpbGwgYmUgZWFzaWVyIHRvIGZvcmVjYXN0IG92ZXJhbGwgdmFsdWVzIGludG8gdGhlIGZ1dHVyZSwgZ2l2ZW4gdGhleSBhcmUgbXVjaCBzbW9vdGhlciwgYW5kIHRoZXNlIGZvcmVjYXN0IG92ZXJhbGwgdmFsdWVzIGNhbiBiZSB1c2VkIHRvIHByZWRpY3QgdGhlIG1vc3QgcG9wdWxhciBmZWF0dXJlIHZhbHVlLgpgYGB7cn0KIyBHZXQgdGhlIGxpc3Qgb2YgZmVhdHVyZXMgSSBuZWVkIHRvIHdvcmsgd2l0aAoKbGlicmFyeShNZXRyaWNzKQoKcTFzID0gZGF0YS5mcmFtZShtYXRyaXgobmNvbD0zLCBucm93PTApKQptZWRpYW5zID0gZGF0YS5mcmFtZShtYXRyaXgobmNvbD0zLCBucm93PTApKQpiZXN0X21lZGlhbnMgPSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPTMsIG5yb3c9MCkpCnEzcyA9IGRhdGEuZnJhbWUobWF0cml4KG5jb2w9MywgbnJvdz0wKSkKZmVhdHVyZV9uYW1lcyA9IHNvcnQoYygiYWNvdXN0aWNuZXNzIiwgImRhbmNlYWJpbGl0eSIsICJpbnN0cnVtZW50YWxuZXNzIiwgImVuZXJneSIsCiAgICAgICAgICAgICAgICAgICJkdXJhdGlvbl9tcyIsICJ2YWxlbmNlIiwgInRlbXBvIiwgImxpdmVuZXNzIiwgImxvdWRuZXNzIiwgInNwZWVjaGluZXNzIikpCmZvcihpIGluIDE5MjE6MjAyMCl7CiAgYW5udWFsX3ZhbCA9IHN1YnNldChkZiwgeWVhcj09aSkKICB0b3BfMTAgPSBmbG9vcihucm93KGFubnVhbF92YWwpKjAuMSkKICBhbm51YWxfdmFsID0gYW5udWFsX3ZhbFtvcmRlcihhbm51YWxfdmFsJHBvcHVsYXJpdHksIGRlY3JlYXNpbmc9VFJVRSksXQogIGJlc3Rfb25lcyA9IGFubnVhbF92YWxbMTp0b3BfMTAsXQoKICBmb3IobmFtZSBpbiBmZWF0dXJlX25hbWVzKXsKICAgIHZhbHMgPSBxdWFudGlsZShhbm51YWxfdmFsWyxuYW1lXSlbMjo0XQogICAgYmVzdF92YWxzID0gcXVhbnRpbGUoYmVzdF9vbmVzWyxuYW1lXSlbMjo0XQogICAgYmVzdF9tZWRpYW5zIDwtIHJiaW5kKGJlc3RfbWVkaWFucywgYyhpLCBuYW1lLCBiZXN0X3ZhbHNbMl0pKQogICAgbWVkaWFucyA8LSByYmluZChtZWRpYW5zLCBjKGksIG5hbWUsIHZhbHNbMl0pKQogIH0KfQoKY29sbmFtZXMobWVkaWFucykgPC1jKCJZZWFyIiwgIkZlYXR1cmUiLCAiVmFsdWUiKQpjb2xuYW1lcyhiZXN0X21lZGlhbnMpIDwtIGMoIlllYXIiLCAiRmVhdHVyZSIsICJWYWx1ZSIpCgpzcGxpdF9tZWRpYW5zIDwtIHNwbGl0KG1lZGlhbnMsIG1lZGlhbnMkRmVhdHVyZSkKc3BsaXRfYmVzdF9tZWRpYW5zIDwtIHNwbGl0KGJlc3RfbWVkaWFucywgYmVzdF9tZWRpYW5zJEZlYXR1cmUpCgpmZWF0dXJlX3F1YW50aWxlcyA9IG1hdHJpeCgwLCBuY29sPWxlbmd0aChmZWF0dXJlX25hbWVzKSwgbnJvdz0xMDApCmJlc3RfZmVhdHVyZV9xdWFudGlsZXMgPSBtYXRyaXgoMCwgbmNvbD1sZW5ndGgoZmVhdHVyZV9uYW1lcyksIG5yb3c9MTAwKQoKZm9yKGkgaW4gMTpsZW5ndGgoZmVhdHVyZV9uYW1lcykpewogIGZvcihqIGluIDE6MTAwKXsKICAgIGZlYXR1cmVfcXVhbnRpbGVzW2osaV0gPC0gc3BsaXRfbWVkaWFuc1tbaV1dW1szXV1bal0KICAgIGJlc3RfZmVhdHVyZV9xdWFudGlsZXNbaixpXSA9IHNwbGl0X2Jlc3RfbWVkaWFuc1tbaV1dW1szXV1bal0KICB9Cn0KCmRpbW5hbWVzKGZlYXR1cmVfcXVhbnRpbGVzKSA8LSBsaXN0KDE5MjE6MjAyMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZV9uYW1lcykKZGltbmFtZXMoYmVzdF9mZWF0dXJlX3F1YW50aWxlcykgPC0gbGlzdCgxOTIxOjIwMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZlYXR1cmVfbmFtZXMpCgoKCgpmb3IoaSBpbiAxOmxlbmd0aChmZWF0dXJlX25hbWVzKSl7CiAgbmFtZSA9IGZlYXR1cmVfbmFtZXNbaV0KICBzY29yZXMgPSBhcy5udW1lcmljKGZlYXR1cmVfcXVhbnRpbGVzWyxpXSkKICBiZXN0X3Njb3JlcyA9IGFzLm51bWVyaWMoYmVzdF9mZWF0dXJlX3F1YW50aWxlc1ssaV0pCiAgbWFwZSA9IG1hcGUoYmVzdF9zY29yZXMsIHNjb3JlcykKICBtYXBlID0gcm91bmQobWFwZSAqIDEwMCwzKQogIHIgID0gY29yKHNjb3JlcywgYmVzdF9zY29yZXMpCiAgcHZhbCA9IHQudGVzdChzY29yZXMsICkKICAjIE5vcm1hbGl6ZSBpdD8/Pz8/IC8gbWFrZSBpdCBhIGZ1bmN0aW9uIG9mIGl0cyBvd24gbWVhbgogIAogIHNtYWxsZXN0ID0gbWluKG1pbihzY29yZXMpLCBtaW4oYmVzdF9zY29yZXMpKQogIGJpZ2dlc3QgPSBtYXgobWF4KHNjb3JlcyksIG1heChiZXN0X3Njb3JlcykpCiAgCiAgcGxvdCh4PTE5MjE6MjAyMCwgeT1zY29yZXMsIGNvbD0xLCB0eXBlPSJsIiwgeWxpbT1jKHNtYWxsZXN0LCBiaWdnZXN0KSwgbWFpbj1uYW1lLCBzdWI9cGFzdGUoIk1BUEU6ICIsIG1hcGUsICIlOyIsICJSOiIsIHIpLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIikKICBsaW5lcyh4PTE5MjE6MjAyMCwgeT1iZXN0X3Njb3JlcywgY29sPTIpCiAgbGVnZW5kKCJ0b3ByaWdodCIsIGx0eT0xLCBjb2w9YygxLDIpLCBsZWdlbmQ9YygiT3ZlcmFsbCIsICJNb3N0IFBvcHVsYXIiKSkKICB0aXRsZSgpCn0KYGBgCiMjIyMjIEluc2lnaHRzOiAKKipBY291c3RpY25lc3MqKjogQSBoaWdoIE1BUEUgd2hlbiBjb21wYXJpbmcgdGhlIG1vc3QgcG9wdWxhciBzb25ncyB3aXRoIHRoZSBvdmVyYWxsIHRyZW5kcyBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBpcyBhIGxhcmdlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIChsaWtlbHkgY2F1c2VkIGluIHRoZSAxOTMwcy0xOTUwcykuIFRoZSBSIHZhbHVlIGlzIGhpZ2ggd2hpY2ggbWVhbnMgdGhlcmUgaXMgYSBoaWdoIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIG1vc3QgcG9wdWxhciBzb25ncyBhbmQgdGhlIG92ZXJhbGwgc29uZ3MuIEJlY2F1c2UgYWNvdXN0aWNuZXNzIHNlZW1zIHRvIGltcGFjdCBwb3B1bGFyIHNvbmdzIGFuZCB0aGVyZSBpcyBhIGxhcmdlIGNoYW5nZSBvdmVyIHRpbWUsIHdlIHdpbGwgbW92ZSBmb3J3YXJkIHdpdGggcHJlZGljdGluZyB0aGUgYWNvdXN0aWNuZXNzIG9mIHNvbmdzIGluIHRoZSBmdXR1cmUuIAoqKkRhbmNlYWJpbGl0eSoqOiBBIGxvdyBNQVBFIGluZGljYXRlcyBub3QgYSBsb3Qgb2YgZGlmZmVyZW5jZSBiZXR3ZWVuIHBvcHVsYXIgc29uZ3MgYW5kIG92ZXJhbGwgc29uZ3MgZGFuY2VhYmlsaXR5LiBIb3dldmVyLCBhIGhpZ2ggUiB2YWx1ZSBtZWFucyB0aGVyZSBpcyBhIGhpZ2ggY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgbW9zdCBwb3B1bGFyIHNvbmdzIGFuZCB0aGUgb3ZlcmFsbCBzb25ncy4gQmVjYXVzZSBkYW5jZWFiaWxpdHkgc2VlbXMgdG8gaW1wYWN0IHBvcHVsYXIgc29uZ3MgKGR1ZSB0byB0aGUgaGlnaCBjb3JyZWxhdGlvbikgYW5kIHRoZXJlIGlzIGEgc29tZSBjaGFuZ2Ugb3ZlciB0aW1lLCB3ZSB3aWxsIG1vdmUgZm9yd2FyZCB3aXRoIHByZWRpY3RpbmcgdGhlIGRhbmNlYWJpbGl0eSBvZiBzb25ncyBpbiB0aGUgZnV0dXJlLiAKKipEdXJhdGlvbiAobXMpKio6IFRoZXJlIGlzIGEgbG93IE1BUEUgd2hpY2ggbWVhbnMgdGhhdCBwb3B1bGFyIHNvbmdzIGhhdmUgYWJvdXQgdGhlIHNhbWUgbGVuZ3RoIGFzIGFsbCBvdGhlciBzb25ncy4gVGhlIFIgdmFsdWUgaXMgcmVsYXRpdmVseSBoaWdoIHdoaWNoIG1lYW5zIHRoZXJlIGlzIGEgaGlnaCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBtb3N0IHBvcHVsYXIgc29uZ3MgYW5kIHRoZSBvdmVyYWxsIHNvbmdzLiBCZWNhdXNlIGR1cmF0aW9uIHNlZW1zIHRvIGltcGFjdCBwb3B1bGFyIHNvbmdzIChkdWUgdG8gdGhlIGhpZ2ggY29ycmVsYXRpb24pIGFuZCB0aGVyZSBpcyBhIHNvbWUgY2hhbmdlIG92ZXIgdGltZSwgd2Ugd2lsbCBtb3ZlIGZvcndhcmQgd2l0aCBwcmVkaWN0aW5nIHRoZSBkdXJhdGlvbiBvZiBzb25ncyBpbiB0aGUgZnV0dXJlLiAKKipFbmVyZ3kqKjogQSBoaWdoIE1BUEUgd2hlbiBjb21wYXJpbmcgdGhlIG1vc3QgcG9wdWxhciBzb25ncyB3aXRoIHRoZSBvdmVyYWxsIHRyZW5kcyBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBpcyBhIGxhcmdlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvLiBUaGUgUiB2YWx1ZSBpcyBoaWdoIHdoaWNoIG1lYW5zIHRoZXJlIGlzIGEgaGlnaCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBtb3N0IHBvcHVsYXIgc29uZ3MgYW5kIHRoZSBvdmVyYWxsIHNvbmdzLiBCZWNhdXNlIGVuZXJneSBzZWVtcyB0byBpbXBhY3QgcG9wdWxhciBzb25ncyAoZHVlIHRvIHRoZSBoaWdoIE1BUEUgYW5kIGNvcnJlbGF0aW9uKSBhbmQgdGhlcmUgYXJlIGxhcmdlIGNoYW5nZXMgb3ZlciB0aW1lLCB3ZSB3aWxsIG1vdmUgZm9yd2FyZCB3aXRoIHByZWRpY3RpbmcgdGhlIGVuZXJneSBvZiBzb25ncyBpbiB0aGUgZnV0dXJlLiAKKipJbnN0cnVtZW50YWxuZXNzKio6IFRoZSBwb3B1bGFyIHNvbmdzIGFuZCBvdmVyYWxsIG11c2ljIHRyZW5kcyBhcmUgcHJldHR5IG11Y2ggdGhlIGV4YWN0IHNhbWUgYWZ0ZXIgdGhlIDE5NTBzLCBpbmRpY2F0aW5nIHRoYXQgaW5zdHJ1bWVudGFsbmVzcyBkb2VzIG5vdCBhZmZlY3QgcG9wdWxhcml0eS4gQmVjYXVzZSBpbnN0cnVtZW50YWxuZXNzIGRvZXMgbm90IGltcGFjdCBwb3B1bGFyIHNvbmdzIGFuZCB0aGVyZSBpcyBhIGZsYXRsaW5lIGFmdGVyIHRoZSAxOTUwcyAoaW5kaWNhdGluZyBubyBjaGFuZ2Ugb3ZlciB0aW1lKSwgd2Ugd2lsbCBub3QgbW92ZSBmb3J3YXJkIHdpdGggcHJlZGljdGluZyB0aGUgaW5zdHJ1bWVudGFsbmVzcyBvZiBzb25ncyBpbiB0aGUgZnV0dXJlLiAKKipMaXZlbmVzcyoqOiBBIGhpZ2ggTUFQRSB3aGVuIGNvbXBhcmluZyB0aGUgbW9zdCBwb3B1bGFyIHNvbmdzIHdpdGggdGhlIG92ZXJhbGwgdHJlbmRzIGluZGljYXRlcyB0aGF0IHRoZXJlIGlzIGEgbGFyZ2UgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28uIFRoZSBSIHZhbHVlIGlzIGhpZ2ggd2hpY2ggbWVhbnMgdGhlcmUgaXMgYSBoaWdoIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIG1vc3QgcG9wdWxhciBzb25ncyBhbmQgdGhlIG92ZXJhbGwgc29uZ3MuIEJlY2F1c2UgbGl2ZW5lc3Mgc2VlbXMgdG8gaW1wYWN0IHBvcHVsYXIgc29uZ3MgKGR1ZSB0byB0aGUgaGlnaCBNQVBFIGFuZCBjb3JyZWxhdGlvbikgYW5kIHRoZXJlIGlzIGEgc29tZSBjaGFuZ2Ugb3ZlciB0aW1lLCB3ZSB3aWxsIG1vdmUgZm9yd2FyZCB3aXRoIHByZWRpY3RpbmcgdGhlIGxpdmVuZXNzIG9mIHNvbmdzIGluIHRoZSBmdXR1cmUuIAoqKkxvdWRuZXNzKio6IEEgaGlnaCBNQVBFIHdoZW4gY29tcGFyaW5nIHRoZSBtb3N0IHBvcHVsYXIgc29uZ3Mgd2l0aCB0aGUgb3ZlcmFsbCB0cmVuZHMgaW5kaWNhdGVzIHRoYXQgdGhlcmUgaXMgYSBsYXJnZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHR3by4gVGhlIFIgdmFsdWUgaXMgaGlnaCB3aGljaCBtZWFucyB0aGVyZSBpcyBhIGhpZ2ggY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgbW9zdCBwb3B1bGFyIHNvbmdzIGFuZCB0aGUgb3ZlcmFsbCBzb25ncy4gQmVjYXVzZSBsb3VkbmVzcyBzZWVtcyB0byBpbXBhY3QgcG9wdWxhciBzb25ncyAoZHVlIHRvIHRoZSBoaWdoIE1BUEUgYW5kIGNvcnJlbGF0aW9uKSBhbmQgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBjaGFuZ2Ugb3ZlciB0aW1lLCB3ZSB3aWxsIG1vdmUgZm9yd2FyZCB3aXRoIHByZWRpY3RpbmcgdGhlIGxvdWRuZXNzIG9mIHNvbmdzIGluIHRoZSBmdXR1cmUuIAoqKlNwZWVjaGluZXNzKio6IEEgaGlnaCBNQVBFIHdoZW4gY29tcGFyaW5nIHRoZSBtb3N0IHBvcHVsYXIgc29uZ3Mgd2l0aCB0aGUgb3ZlcmFsbCB0cmVuZHMgaW5kaWNhdGVzIHRoYXQgdGhlcmUgaXMgYSBsYXJnZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHR3by4gSXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHRoZSBkcml2ZXIgb2YgdGhlIGhpZ2ggTUFQRSBpcyBkdWUgdG8gdGhlIHR3byBsYXJnZSBzcGlrZXMgYmV0d2VlbiAxOTMwIGFuZCAxOTUwLCB3aGlsZSBzcGVlY2hpbmVzcyBsZXZlbHMgYmV0d2VlbiBwb3B1bGFyIHNvbmdzIGFuZCB0aGUgb3ZlcmFsbCBpbmR1c3RyeSBpbiB0aGUgbGFzdCA3MCB5ZWFycyBoYXZlIGdlbmVyYWxseSBiZWVuIHRoZSBzYW1lLiBUaGUgUiB2YWx1ZSBpcyBsb3cgd2hpY2ggbWVhbnMgdGhlcmUgaXMgYSBsb3cgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgbW9zdCBwb3B1bGFyIHNvbmdzIGFuZCB0aGUgb3ZlcmFsbCBzb25ncy4gV2Ugd2lsbCBub3QgbW92ZSBmb3J3YXJkIHdpdGggcHJlZGljdGluZyBzcGVlY2hpbmVzcywgZHVlIHRvIHRoZSBsYWNrIG9mIGNoYW5nZSBpbiBzcGVlY2hpbmVzcyBvdmVyIHRpbWUgYW5kIGxvdyBSLgoqKlRlbXBvKio6IFRoZSBNQVBFIGlzIGxvdywgaW5pZGNhdGluZyB0aGF0IHRoZXJlIGlzbid0IGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0ZW1wbyBiZXR3ZWVuIHRoZSBwb3B1bGFyIHNvbmdzIGFuZCB0aGUgb3ZlcmFsbCBtdXNpYyB0cmVuZHMuIFRoZSBSIGlzIHJlbGF0aXZlbHkgaGlnaCwgc28gdGhlcmUgaXMgcG9zc2libHkgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHBvcHVsYXIgc29uZ3MgYW5kIHRoZSBvdmVyYWxsIHNvbmdzLiBCZWNhdXNlIHRlbXBvIHNlZW1zIHRvIGltcGFjdCBwb3B1bGFyIHNvbmdzIChkdWUgdG8gdGhlIGhpZ2ggY29ycmVsYXRpb24pIGFuZCB0aGVyZSBpcyBhIHNvbWUgY2hhbmdlIG92ZXIgdGltZSwgd2Ugd2lsbCBtb3ZlIGZvcndhcmQgd2l0aCBwcmVkaWN0aW5nIHRoZSB0ZW1wbyBvZiBzb25ncyBpbiB0aGUgZnV0dXJlLiAKKipWYWxlbmNlKio6IEEgaGlnaCBNQVBFIHdoZW4gY29tcGFyaW5nIHRoZSBtb3N0IHBvcHVsYXIgc29uZ3Mgd2l0aCB0aGUgb3ZlcmFsbCB0cmVuZHMgaW5kaWNhdGVzIHRoYXQgdGhlcmUgaXMgYSBsYXJnZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHR3byBpbiB0ZXJtcyBvZiB2YWxlbmNlLiBUaGUgUiB2YWx1ZSBpcyBoaWdoIHdoaWNoIG1lYW5zIHRoZXJlIGlzIGEgaGlnaCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBtb3N0IHBvcHVsYXIgc29uZ3MgYW5kIHRoZSBvdmVyYWxsIHNvbmdzLiBCZWNhdXNlIHZhbGVuY2Ugc2VlbXMgdG8gaW1wYWN0IHBvcHVsYXIgc29uZ3MgKGR1ZSB0byB0aGUgaGlnaCBNQVBFIGFuZCBoaWdoIGNvcnJlbGF0aW9uKSBhbmQgdGhlcmUgaXMgYSBzb21lIGNoYW5nZSBvdmVyIHRpbWUsIHdlIHdpbGwgbW92ZSBmb3J3YXJkIHdpdGggcHJlZGljdGluZyB0aGUgdmFsZW5jZSBvZiBzb25ncyBpbiB0aGUgZnV0dXJlLiAKCgoKIyBUcmFpbiB0aW1lIHNlcmllcyBtb2RlbHMgdG8gZm9yZWNhc3QgdGhlIGZ1dHVyZSBtb2RlbHMuCmBgYHtyfQojIFNldCB1cCB0aGUgbGlicmFyaWVzIGFuZCB0aGUgdHJhaW5pbmcvdGVzdGluZyBhbW91bnRzCmxpYnJhcnkoInNtb290aCIpCmxpYnJhcnkoImZvcmVjYXN0IikKbGlicmFyeSgibm5mb3IiKQp0cmFpbmluZy5wZXJjZW50ID0gMC45NQpuVHJhaW4gPSAxMDAqdHJhaW5pbmcucGVyY2VudApuVGVzdCA9IDEwMCooMS10cmFpbmluZy5wZXJjZW50KQpgYGAKCiMjIEFjY291c3RpY25lc3MgTW9kZWxzCgpgYGB7cn0KYWNvdXN0aWNuZXNzID0gdHMoYXMubnVtZXJpYyhmZWF0dXJlX3F1YW50aWxlc1ssImFjb3VzdGljbmVzcyJdKSAsIHN0YXJ0PTE5MjEpCmFjb3VzdGljbmVzcy50cmFpbiA9IHN1YnNldChhY291c3RpY25lc3MsIHN0YXJ0PTEsIGVuZD1uVHJhaW4pCmFjb3VzdGljbmVzcy50ZXN0ID0gc3Vic2V0KGFjb3VzdGljbmVzcywgc3RhcnQgPSAoblRyYWluKzEpLCBlbmQgPShuVHJhaW4rblRlc3QpKQoKI3NlcwphY291c3RpY25lc3MudHJhaW4uc2VzIDwtIHNlcyhhY291c3RpY25lc3MudHJhaW4sIGg9blRlc3QpCmFjb3VzdGljbmVzcy5zZXMubWFwZSA9IG1hcGUoYWNvdXN0aWNuZXNzLnRyYWluLnNlcyRtZWFuLCBhY291c3RpY25lc3MudGVzdCkKcGxvdChhY291c3RpY25lc3MudHJhaW4uc2VzLCBtYWluPXBhc3RlKCJBY291c3RpY25lc3MiLCAiU0VTIiksIHN1Yj1wYXN0ZSgiTUFQRToiLCByb3VuZChhY291c3RpY25lc3Muc2VzLm1hcGUqMTAwLCAzKSwgIiUiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKGFjb3VzdGljbmVzcykKCiNTQVJJTUEKYWNvdXN0aWNuZXNzLnNhcmltYS5tb2RlbCA8LSBhdXRvLmFyaW1hKGFjb3VzdGljbmVzcy50cmFpbikKYWNvdXN0aWNuZXNzLnNhcmltYSA8LSBmb3JlY2FzdChhY291c3RpY25lc3Muc2FyaW1hLm1vZGVsLCBoPW5UZXN0KQphY291c3RpY25lc3Muc2FyaW1hLm1hcGUgPSBtYXBlKGFjb3VzdGljbmVzcy5zYXJpbWEkbWVhbiwgYWNvdXN0aWNuZXNzLnRlc3QpCnBsb3QoYWNvdXN0aWNuZXNzLnNhcmltYSwgbWFpbj1wYXN0ZSgiQWNvdXN0aWNuZXNzIiwgIlNBUklNQSIpLCBzdWI9cGFzdGUoIk1BUEU6Iiwgcm91bmQoYWNvdXN0aWNuZXNzLnNhcmltYS5tYXBlKjEwMCwzKSwgIiUiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKGFjb3VzdGljbmVzcykKCiNOZXVyYWwgTmV0d29yawphY291c3RpY25lc3MudHJhaW4ubm4gPC0gZWxtKGFjb3VzdGljbmVzcy50cmFpbikKYWNvdXN0aWNuZXNzLm5uLmZvcmVjYXN0IDwtIGZvcmVjYXN0KGFjb3VzdGljbmVzcy50cmFpbi5ubiwgaD1uVGVzdCkKYWNvdXN0aWNuZXNzLm5uLm1hcGUgPSBtYXBlKGFjb3VzdGljbmVzcy5ubi5mb3JlY2FzdCRtZWFuLCBhY291c3RpY25lc3MudGVzdCkKcGxvdChhY291c3RpY25lc3MsIG1haW49cGFzdGUoIkFjb3VzdGljbmVzcyIsICJOTiIpLCBzdWI9cGFzdGUoIk1BUEU6Iiwgcm91bmQoYWNvdXN0aWNuZXNzLm5uLm1hcGUqMTAwLCAzKSwgIiUiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKHRzKGFjb3VzdGljbmVzcy5ubi5mb3JlY2FzdCRtZWFuLCBzdGFydD0xOTIxK25UcmFpbiksIGNvbD0yKQpgYGAKSGVyZSB3ZSBzZWUgdGhhdCB0aGUgYmVzdCBtZXRob2QgdG8gcHJlZGljdCBmdXR1cmUgYWNvdXN0aWNuZXNzIG1lZGlhbiB2YWx1ZXMgZm9yIHRoZSBvdmVyYWxsIGRhdGEgc2V0IGlzIHRocm91Z2ggU0VTLiBIb3dldmVyLCBnaXZlbiB0aGF0IHRoaXMgYmVzdCBNQVBFIGlzIHJvdWdobHkgMzclLCB0aGlzIGZlYXR1cmUgY2Fubm90IGJlIHJlbGlhYmx5IGZvcmVjYXN0IGludG8gdGhlIGZ1dHVyZS4KICAKCgoKIyMgRW5lcmd5IG1vZGVscwpgYGB7cn0KZW5lcmd5ID0gdHMoYXMubnVtZXJpYyhmZWF0dXJlX3F1YW50aWxlc1ssImVuZXJneSJdKSAsIHN0YXJ0PTE5MjEpCmVuZXJneS50cmFpbiA9IHN1YnNldChlbmVyZ3ksIHN0YXJ0PTEsIGVuZD1uVHJhaW4pCmVuZXJneS50ZXN0ID0gc3Vic2V0KGVuZXJneSwgc3RhcnQgPSAoblRyYWluKzEpLCBlbmQgPShuVHJhaW4rblRlc3QpKQoKI1NFUwplbmVyZ3kudHJhaW4uc2VzIDwtIHNlcyhlbmVyZ3kudHJhaW4sIGg9blRlc3QpCmVuZXJneS5zZXMubWFwZSA9IG1hcGUoZW5lcmd5LnRyYWluLnNlcyRtZWFuLCBlbmVyZ3kudGVzdCkKcGxvdChlbmVyZ3kudHJhaW4uc2VzLCBtYWluPXBhc3RlKCJFbmVyZ3kiLCAiU0VTIiksIHN1Yj1wYXN0ZSgiTUFQRToiLCByb3VuZChlbmVyZ3kuc2VzLm1hcGUqIDEwMCwgMyksICIlIiksIHhsYWI9IlllYXIiLCB5bGFiPSJNZWRpYW4gVmFsdWUiKQpsaW5lcyhlbmVyZ3kpCgojU0FSSU1BCmVuZXJneS5zYXJpbWEubW9kZWwgPC0gYXV0by5hcmltYShlbmVyZ3kudHJhaW4pCmVuZXJneS5zYXJpbWEgPC0gZm9yZWNhc3QoZW5lcmd5LnNhcmltYS5tb2RlbCwgaD1uVGVzdCkKZW5lcmd5LnNhcmltYS5tYXBlID0gbWFwZShlbmVyZ3kuc2FyaW1hJG1lYW4sIGVuZXJneS50ZXN0KQpwbG90KGVuZXJneS5zYXJpbWEsIG1haW49cGFzdGUoIkVuZXJneSIsICJTQVJJTUEiKSwgc3ViPXBhc3RlKCJNQVBFOiIsIHJvdW5kKGVuZXJneS5zYXJpbWEubWFwZSogMTAwLCAzKSwgIiUiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKGVuZXJneSkKCiNOZXVyYWwgTmV0d29yawplbmVyZ3kudHJhaW4ubm4gPC0gZWxtKGVuZXJneS50cmFpbikKZW5lcmd5Lm5uLmZvcmVjYXN0IDwtIGZvcmVjYXN0KGVuZXJneS50cmFpbi5ubiwgaD1uVGVzdCkKZW5lcmd5Lm5uLm1hcGUgPSBtYXBlKGVuZXJneS5ubi5mb3JlY2FzdCRtZWFuLCBlbmVyZ3kudGVzdCkKcGxvdChlbmVyZ3ksIG1haW49cGFzdGUoIkVuZXJneSIsICJOTiIpLCBzdWI9cGFzdGUoIk1BUEU6Iiwgcm91bmQoZW5lcmd5Lm5uLm1hcGUqIDEwMCwgMyksICIlIiksIHhsYWI9IlllYXIiLCB5bGFiPSJNZWRpYW4gVmFsdWUiKQpsaW5lcyh0cyhlbmVyZ3kubm4uZm9yZWNhc3QkbWVhbiwgc3RhcnQ9MTkyMStuVHJhaW4pLCBjb2w9MikKYGBgCkhlcmUgd2Ugc2VlIHRoYXQgdGhlIGJlc3QgbWV0aG9kIHRvIHByZWRpY3QgZnV0dXJlIGVuZXJneSBtZWRpYW4gdmFsdWVzIGZvciB0aGUgb3ZlcmFsbCBkYXRhIHNldCBpcyB0aHJvdWdoIFNFUy4gR2l2ZW4gdGhhdCB0aGlzIGJlc3QgTUFQRSBpcyByb3VnaGx5IDglLCB0aGlzIGZlYXR1cmUgY2FuIGJlIGZhaXJseSByZWxpYWJseSBmb3JlY2FzdCBpbnRvIHRoZSBmdXR1cmUuCiAgCgojIyBEYW5jZWFiaWxpdHkgbW9kZWxzCmBgYHtyfQpkYW5jZWFiaWxpdHkgPSB0cyhhcy5udW1lcmljKGZlYXR1cmVfcXVhbnRpbGVzWywiZGFuY2VhYmlsaXR5Il0pICwgc3RhcnQ9MTkyMSkKZGFuY2VhYmlsaXR5LnRyYWluID0gc3Vic2V0KGRhbmNlYWJpbGl0eSwgc3RhcnQ9MSwgZW5kPW5UcmFpbikKZGFuY2VhYmlsaXR5LnRlc3QgPSBzdWJzZXQoZGFuY2VhYmlsaXR5LCBzdGFydCA9IChuVHJhaW4rMSksIGVuZCA9KG5UcmFpbituVGVzdCkpCgojU0VTCmRhbmNlYWJpbGl0eS50cmFpbi5zZXMgPC0gc2VzKGRhbmNlYWJpbGl0eS50cmFpbiwgaD1uVGVzdCkKZGFuY2VhYmlsaXR5LnNlcy5tYXBlID0gbWFwZShkYW5jZWFiaWxpdHkudHJhaW4uc2VzJG1lYW4sIGRhbmNlYWJpbGl0eS50ZXN0KQpwbG90KGRhbmNlYWJpbGl0eS50cmFpbi5zZXMsIG1haW49cGFzdGUoImRhbmNlYWJpbGl0eSIsICJTRVMiKSwgc3ViPXBhc3RlKCJNQVBFOiIsIHJvdW5kKGRhbmNlYWJpbGl0eS5zZXMubWFwZSogMTAwLCAzKSwgIiUiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKGRhbmNlYWJpbGl0eSkKCiNTQVJJTUEKZGFuY2VhYmlsaXR5LnNhcmltYS5tb2RlbCA8LSBhdXRvLmFyaW1hKGRhbmNlYWJpbGl0eS50cmFpbikKZGFuY2VhYmlsaXR5LnNhcmltYSA8LSBmb3JlY2FzdChkYW5jZWFiaWxpdHkuc2FyaW1hLm1vZGVsLCBoPW5UZXN0KQpkYW5jZWFiaWxpdHkuc2FyaW1hLm1hcGUgPSBtYXBlKGRhbmNlYWJpbGl0eS5zYXJpbWEkbWVhbiwgZGFuY2VhYmlsaXR5LnRlc3QpCnBsb3QoZGFuY2VhYmlsaXR5LnNhcmltYSwgbWFpbj1wYXN0ZSgiZGFuY2VhYmlsaXR5IiwgIlNBUklNQSIpLCBzdWI9cGFzdGUoIk1BUEU6Iiwgcm91bmQoZGFuY2VhYmlsaXR5LnNhcmltYS5tYXBlKiAxMDAsIDMpLCAiJSIpLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIikKbGluZXMoZGFuY2VhYmlsaXR5KQoKI05ldXJhbCBOZXR3b3JrCmRhbmNlYWJpbGl0eS50cmFpbi5ubiA8LSBlbG0oZGFuY2VhYmlsaXR5LnRyYWluKQpkYW5jZWFiaWxpdHkubm4uZm9yZWNhc3QgPC0gZm9yZWNhc3QoZGFuY2VhYmlsaXR5LnRyYWluLm5uLCBoPW5UZXN0KQpkYW5jZWFiaWxpdHkubm4ubWFwZSA9IG1hcGUoZGFuY2VhYmlsaXR5Lm5uLmZvcmVjYXN0JG1lYW4sIGRhbmNlYWJpbGl0eS50ZXN0KQpwbG90KGRhbmNlYWJpbGl0eSwgbWFpbj1wYXN0ZSgiZGFuY2VhYmlsaXR5IiwgIk5OIiksIHN1Yj1wYXN0ZSgiTUFQRToiLCByb3VuZChkYW5jZWFiaWxpdHkubm4ubWFwZSogMTAwLCAzKSwgIiUiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKHRzKGRhbmNlYWJpbGl0eS5ubi5mb3JlY2FzdCRtZWFuLCBzdGFydD0xOTIxK25UcmFpbiksIGNvbD0yKQpgYGAKSGVyZSB3ZSBzZWUgdGhhdCB0aGUgYmVzdCBtZXRob2QgdG8gcHJlZGljdCBmdXR1cmUgZGFuY2VhYmlsaXR5IG1lZGlhbiB2YWx1ZXMgZm9yIHRoZSBvdmVyYWxsIGRhdGEgc2V0IGlzIHRocm91Z2ggTk4uIEhvd2V2ZXIsIGdpdmVuIHRoYXQgdGhpcyBiZXN0IE1BUEUgaXMgcm91Z2hseSAxMC40JSwgdGhpcyBmZWF0dXJlIGNhbm5vdCBiZSByZWxpYWJseSBmb3JlY2FzdCBpbnRvIHRoZSBmdXR1cmUuCiAgCgojIyBEdXJhdGlvbiBtb2RlbHMKCmBgYHtyfQpkdXJhdGlvbiA9IHRzKGFzLm51bWVyaWMoZmVhdHVyZV9xdWFudGlsZXNbLCJkdXJhdGlvbl9tcyJdKSAsIHN0YXJ0PTE5MjEpCmR1cmF0aW9uLnRyYWluID0gc3Vic2V0KGR1cmF0aW9uLCBzdGFydD0xLCBlbmQ9blRyYWluKQpkdXJhdGlvbi50ZXN0ID0gc3Vic2V0KGR1cmF0aW9uLCBzdGFydCA9IChuVHJhaW4rMSksIGVuZCA9KG5UcmFpbituVGVzdCkpCgojU0VTCmR1cmF0aW9uLnRyYWluLnNlcyA8LSBzZXMoZHVyYXRpb24udHJhaW4sIGg9blRlc3QpCmR1cmF0aW9uLnNlcy5tYXBlID0gbWFwZShkdXJhdGlvbi50cmFpbi5zZXMkbWVhbiwgZHVyYXRpb24udGVzdCkKcGxvdChkdXJhdGlvbi50cmFpbi5zZXMsIG1haW49cGFzdGUoIkR1cmF0aW9uIiwgIlNFUyIpLCBzdWI9cGFzdGUoIk1BUEU6Iixyb3VuZChkdXJhdGlvbi5zZXMubWFwZSoxMDAsIDMpLCAiJSIpLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIikKbGluZXMoZHVyYXRpb24pCgojU0FSSU1BCmR1cmF0aW9uLnNhcmltYS5tb2RlbCA8LSBhdXRvLmFyaW1hKGR1cmF0aW9uLnRyYWluKQpkdXJhdGlvbi5zYXJpbWEgPC0gZm9yZWNhc3QoZHVyYXRpb24uc2FyaW1hLm1vZGVsLCBoPW5UZXN0KQpkdXJhdGlvbi5zYXJpbWEubWFwZSA9IG1hcGUoZHVyYXRpb24uc2FyaW1hJG1lYW4sIGR1cmF0aW9uLnRlc3QpCnBsb3QoZHVyYXRpb24uc2FyaW1hLCBtYWluPXBhc3RlKCJEdXJhdGlvbiIsICJTQVJJTUEiKSwgc3ViPXBhc3RlKCJNQVBFOiIsIHJvdW5kKGR1cmF0aW9uLnNhcmltYS5tYXBlKjEwMCwgMyksICIlIiksIHhsYWI9IlllYXIiLCB5bGFiPSJNZWRpYW4gVmFsdWUiKQpsaW5lcyhkdXJhdGlvbikKCgojTmV1cmFsIE5ldHdvcmsKZHVyYXRpb24udHJhaW4ubm4gPC0gZWxtKGR1cmF0aW9uLnRyYWluKQpkdXJhdGlvbi5ubi5mb3JlY2FzdCA8LSBmb3JlY2FzdChkdXJhdGlvbi50cmFpbi5ubiwgaD1uVGVzdCkKZHVyYXRpb24ubm4ubWFwZSA9IG1hcGUoZHVyYXRpb24ubm4uZm9yZWNhc3QkbWVhbiwgZHVyYXRpb24udGVzdCkKcGxvdChkdXJhdGlvbiwgbWFpbj1wYXN0ZSgiRHVyYXRpb24iLCAiTk4iKSwgc3ViPXBhc3RlKCJNQVBFOiIsIHJvdW5kKGR1cmF0aW9uLm5uLm1hcGUqMTAwLCAzKSwgIiUiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKHRzKGR1cmF0aW9uLm5uLmZvcmVjYXN0JG1lYW4sIHN0YXJ0PTE5MjErblRyYWluKSwgY29sPTIpCmBgYApIZXJlIHdlIHNlZSB0aGF0IHRoZSBiZXN0IG1ldGhvZCB0byBwcmVkaWN0IGZ1dHVyZSBkdXJhdGlvbiBtZWRpYW4gdmFsdWVzIGZvciB0aGUgb3ZlcmFsbCBkYXRhIHNldCBpcyB0aHJvdWdoIE5OLiBHaXZlbiB0aGF0IHRoaXMgYmVzdCBNQVBFIGlzIHJvdWdobHkgOCUsIHRoaXMgZmVhdHVyZSBjYW4gYmUgZmFpcmx5IHJlbGlhYmx5IGZvcmVjYXN0IGludG8gdGhlIGZ1dHVyZS4KICAKCiMjIFZhbGVuY2UKYGBge3J9CnZhbGVuY2UgPSB0cyhhcy5udW1lcmljKGZlYXR1cmVfcXVhbnRpbGVzWywidmFsZW5jZSJdKSAsIHN0YXJ0PTE5MjEpCnZhbGVuY2UudHJhaW4gPSBzdWJzZXQodmFsZW5jZSwgc3RhcnQ9MSwgZW5kPW5UcmFpbikKdmFsZW5jZS50ZXN0ID0gc3Vic2V0KHZhbGVuY2UsIHN0YXJ0ID0gKG5UcmFpbisxKSwgZW5kID0oblRyYWluK25UZXN0KSkKCiNTRVMKdmFsZW5jZS50cmFpbi5zZXMgPC0gc2VzKHZhbGVuY2UudHJhaW4sIGg9blRlc3QpCnZhbGVuY2Uuc2VzLm1hcGUgPSBtYXBlKHZhbGVuY2UudHJhaW4uc2VzJG1lYW4sIHZhbGVuY2UudGVzdCkKcGxvdCh2YWxlbmNlLnRyYWluLnNlcywgbWFpbj1wYXN0ZSgidmFsZW5jZSIsICJTRVMiKSwgc3ViPXBhc3RlKCJNQVBFOiIscm91bmQodmFsZW5jZS5zZXMubWFwZSoxMDAsIDMpLCAiJSIpLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIikKbGluZXModmFsZW5jZSkKCiNTQVJJTUEKdmFsZW5jZS5zYXJpbWEubW9kZWwgPC0gYXV0by5hcmltYSh2YWxlbmNlLnRyYWluKQp2YWxlbmNlLnNhcmltYSA8LSBmb3JlY2FzdCh2YWxlbmNlLnNhcmltYS5tb2RlbCwgaD1uVGVzdCkKdmFsZW5jZS5zYXJpbWEubWFwZSA9IG1hcGUodmFsZW5jZS5zYXJpbWEkbWVhbiwgdmFsZW5jZS50ZXN0KQpwbG90KHZhbGVuY2Uuc2FyaW1hLCBtYWluPXBhc3RlKCJ2YWxlbmNlIiwgIlNBUklNQSIpLCBzdWI9cGFzdGUoIk1BUEU6Iiwgcm91bmQodmFsZW5jZS5zYXJpbWEubWFwZSoxMDAsIDMpLCAiJSIpLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIikKbGluZXModmFsZW5jZSkKCgojTmV1cmFsIE5ldHdvcmsKdmFsZW5jZS50cmFpbi5ubiA8LSBlbG0odmFsZW5jZS50cmFpbikKdmFsZW5jZS5ubi5mb3JlY2FzdCA8LSBmb3JlY2FzdCh2YWxlbmNlLnRyYWluLm5uLCBoPW5UZXN0KQp2YWxlbmNlLm5uLm1hcGUgPSBtYXBlKHZhbGVuY2Uubm4uZm9yZWNhc3QkbWVhbiwgdmFsZW5jZS50ZXN0KQpwbG90KHZhbGVuY2UsIG1haW49cGFzdGUoInZhbGVuY2UiLCAiTk4iKSwgc3ViPXBhc3RlKCJNQVBFOiIsIHJvdW5kKHZhbGVuY2Uubm4ubWFwZSoxMDAsIDMpLCAiJSIpLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIikKbGluZXModHModmFsZW5jZS5ubi5mb3JlY2FzdCRtZWFuLCBzdGFydD0xOTIxK25UcmFpbiksIGNvbD0yKQpgYGAKIyMjIyMgSW5zaWdodHM6ClJlbGF0aXZlbHkgbG93ZXIgTUFQRSBpbmRpY2F0ZXMgdGhhdCB3ZSBjYW4gcHJlZGljdCB2YWxlbmNlIG92ZXIgdGltZS4gVGhlIGJlc3QgbW9kZWwgdG8gdXNlIGlzIHRoZSBTQVJJTUEgbW9kZWwgYmVjYXVzZSBpdCBoYXMgdGhlIGxvd2VzdCBNQVBFIGF0IDYuNyUuIAoKIyMgVGVtcG8gbW9kZWwKCmBgYHtyfQp0ZW1wbyA9IHRzKGFzLm51bWVyaWMoZmVhdHVyZV9xdWFudGlsZXNbLCJ0ZW1wbyJdKSAsIHN0YXJ0PTE5MjEpCnRlbXBvLnRyYWluID0gc3Vic2V0KHRlbXBvLCBzdGFydD0xLCBlbmQ9blRyYWluKQp0ZW1wby50ZXN0ID0gc3Vic2V0KHRlbXBvLCBzdGFydCA9IChuVHJhaW4rMSksIGVuZCA9KG5UcmFpbituVGVzdCkpCgojU0VTCnRlbXBvLnRyYWluLnNlcyA8LSBzZXModGVtcG8udHJhaW4sIGg9blRlc3QpCnRlbXBvLnNlcy5tYXBlID0gbWFwZSh0ZW1wby50cmFpbi5zZXMkbWVhbiwgdGVtcG8udGVzdCkKcGxvdCh0ZW1wby50cmFpbi5zZXMsIG1haW49cGFzdGUoInRlbXBvIiwgIlNFUyIpLCBzdWI9cGFzdGUoIk1BUEU6Iixyb3VuZCh0ZW1wby5zZXMubWFwZSoxMDAsIDMpLCAiJSIpLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIikKbGluZXModGVtcG8pCgojU0FSSU1BCnRlbXBvLnNhcmltYS5tb2RlbCA8LSBhdXRvLmFyaW1hKHRlbXBvLnRyYWluKQp0ZW1wby5zYXJpbWEgPC0gZm9yZWNhc3QodGVtcG8uc2FyaW1hLm1vZGVsLCBoPW5UZXN0KQp0ZW1wby5zYXJpbWEubWFwZSA9IG1hcGUodGVtcG8uc2FyaW1hJG1lYW4sIHRlbXBvLnRlc3QpCnBsb3QodGVtcG8uc2FyaW1hLCBtYWluPXBhc3RlKCJ0ZW1wbyIsICJTQVJJTUEiKSwgc3ViPXBhc3RlKCJNQVBFOiIsIHJvdW5kKHRlbXBvLnNhcmltYS5tYXBlKjEwMCwgMyksICIlIiksIHhsYWI9IlllYXIiLCB5bGFiPSJNZWRpYW4gVmFsdWUiKQpsaW5lcyh0ZW1wbykKCgojTmV1cmFsIE5ldHdvcmsKdGVtcG8udHJhaW4ubm4gPC0gZWxtKHRlbXBvLnRyYWluKQp0ZW1wby5ubi5mb3JlY2FzdCA8LSBmb3JlY2FzdCh0ZW1wby50cmFpbi5ubiwgaD1uVGVzdCkKdGVtcG8ubm4ubWFwZSA9IG1hcGUodGVtcG8ubm4uZm9yZWNhc3QkbWVhbiwgdGVtcG8udGVzdCkKcGxvdCh0ZW1wbywgbWFpbj1wYXN0ZSgidGVtcG8iLCAiTk4iKSwgc3ViPXBhc3RlKCJNQVBFOiIsIHJvdW5kKHRlbXBvLm5uLm1hcGUqMTAwLCAzKSwgIiUiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKHRzKHRlbXBvLm5uLmZvcmVjYXN0JG1lYW4sIHN0YXJ0PTE5MjErblRyYWluKSwgY29sPTIpCmBgYAojIyMjIyBJbnNpZ2h0czoKSGVyZSB3ZSBzZWUgdGhhdCB0aGUgYmVzdCBtZXRob2QgdG8gcHJlZGljdCBmdXR1cmUgdGVtcG8gbWVkaWFuIHZhbHVlcyBmb3IgdGhlIG92ZXJhbGwgZGF0YSBzZXQgaXMgdGhyb3VnaCBTRVMuIEdpdmVuIHRoYXQgdGhpcyBiZXN0IE1BUEUgaXMgcm91Z2hseSAxJSwgdGhpcyBmZWF0dXJlIGNhbiBiZSBmYWlybHkgcmVsaWFibHkgZm9yZWNhc3QgaW50byB0aGUgZnV0dXJlLgogIAoKIyMgTGl2ZW5lc3MKYGBge3J9CmxpdmVuZXNzID0gdHMoYXMubnVtZXJpYyhmZWF0dXJlX3F1YW50aWxlc1ssImxpdmVuZXNzIl0pICwgc3RhcnQ9MTkyMSkKbGl2ZW5lc3MudHJhaW4gPSBzdWJzZXQobGl2ZW5lc3MsIHN0YXJ0PTEsIGVuZD1uVHJhaW4pCmxpdmVuZXNzLnRlc3QgPSBzdWJzZXQobGl2ZW5lc3MsIHN0YXJ0ID0gKG5UcmFpbisxKSwgZW5kID0oblRyYWluK25UZXN0KSkKCiNTRVMKbGl2ZW5lc3MudHJhaW4uc2VzIDwtIHNlcyhsaXZlbmVzcy50cmFpbiwgaD1uVGVzdCkKbGl2ZW5lc3Muc2VzLm1hcGUgPSBtYXBlKGxpdmVuZXNzLnRyYWluLnNlcyRtZWFuLCBsaXZlbmVzcy50ZXN0KQpwbG90KGxpdmVuZXNzLnRyYWluLnNlcywgbWFpbj1wYXN0ZSgibGl2ZW5lc3MiLCAiU0VTIiksIHN1Yj1wYXN0ZSgiTUFQRToiLHJvdW5kKGxpdmVuZXNzLnNlcy5tYXBlKjEwMCwgMyksICIlIiksIHhsYWI9IlllYXIiLCB5bGFiPSJNZWRpYW4gVmFsdWUiKQpsaW5lcyhsaXZlbmVzcykKCiNTQVJJTUEKbGl2ZW5lc3Muc2FyaW1hLm1vZGVsIDwtIGF1dG8uYXJpbWEobGl2ZW5lc3MudHJhaW4pCmxpdmVuZXNzLnNhcmltYSA8LSBmb3JlY2FzdChsaXZlbmVzcy5zYXJpbWEubW9kZWwsIGg9blRlc3QpCmxpdmVuZXNzLnNhcmltYS5tYXBlID0gbWFwZShsaXZlbmVzcy5zYXJpbWEkbWVhbiwgbGl2ZW5lc3MudGVzdCkKcGxvdChsaXZlbmVzcy5zYXJpbWEsIG1haW49cGFzdGUoImxpdmVuZXNzIiwgIlNBUklNQSIpLCBzdWI9cGFzdGUoIk1BUEU6Iiwgcm91bmQobGl2ZW5lc3Muc2FyaW1hLm1hcGUqMTAwLCAzKSwgIiUiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKGxpdmVuZXNzKQoKCiNOZXVyYWwgTmV0d29yawpsaXZlbmVzcy50cmFpbi5ubiA8LSBlbG0obGl2ZW5lc3MudHJhaW4pCmxpdmVuZXNzLm5uLmZvcmVjYXN0IDwtIGZvcmVjYXN0KGxpdmVuZXNzLnRyYWluLm5uLCBoPW5UZXN0KQpsaXZlbmVzcy5ubi5tYXBlID0gbWFwZShsaXZlbmVzcy5ubi5mb3JlY2FzdCRtZWFuLCBsaXZlbmVzcy50ZXN0KQpwbG90KGxpdmVuZXNzLCBtYWluPXBhc3RlKCJsaXZlbmVzcyIsICJOTiIpLCBzdWI9cGFzdGUoIk1BUEU6Iiwgcm91bmQobGl2ZW5lc3Mubm4ubWFwZSoxMDAsIDMpLCAiJSIpLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIikKbGluZXModHMobGl2ZW5lc3Mubm4uZm9yZWNhc3QkbWVhbiwgc3RhcnQ9MTkyMStuVHJhaW4pLCBjb2w9MikKYGBgCiMjIyMjIEluc2lnaHRzOgpIZXJlIHdlIHNlZSB0aGF0IHRoZSBiZXN0IG1ldGhvZCB0byBwcmVkaWN0IGZ1dHVyZSBsaXZlbmVzcyBtZWRpYW4gdmFsdWVzIGZvciB0aGUgb3ZlcmFsbCBkYXRhIHNldCBpcyB0aHJvdWdoIFNBUklNQSBHaXZlbiB0aGF0IHRoaXMgYmVzdCBNQVBFIGlzIHJvdWdobHkgMi42JSwgdGhpcyBmZWF0dXJlIGNhbiBiZSBmYWlybHkgcmVsaWFibHkgZm9yZWNhc3QgaW50byB0aGUgZnV0dXJlLgoKIyMgTG91ZG5lc3MKYGBge3J9CmxvdWRuZXNzID0gdHMoYXMubnVtZXJpYyhmZWF0dXJlX3F1YW50aWxlc1ssImxvdWRuZXNzIl0pICwgc3RhcnQ9MTkyMSkKbG91ZG5lc3MudHJhaW4gPSBzdWJzZXQobG91ZG5lc3MsIHN0YXJ0PTEsIGVuZD1uVHJhaW4pCmxvdWRuZXNzLnRlc3QgPSBzdWJzZXQobG91ZG5lc3MsIHN0YXJ0ID0gKG5UcmFpbisxKSwgZW5kID0oblRyYWluK25UZXN0KSkKCiNTRVMKbG91ZG5lc3MudHJhaW4uc2VzIDwtIHNlcyhsb3VkbmVzcy50cmFpbiwgaD1uVGVzdCkKbG91ZG5lc3Muc2VzLm1hcGUgPSBtYXBlKGxvdWRuZXNzLnRyYWluLnNlcyRtZWFuLCBsb3VkbmVzcy50ZXN0KQpwbG90KGxvdWRuZXNzLnRyYWluLnNlcywgbWFpbj1wYXN0ZSgibG91ZG5lc3MiLCAiU0VTIiksIHN1Yj1wYXN0ZSgiTUFQRToiLHJvdW5kKGxvdWRuZXNzLnNlcy5tYXBlKjEwMCwgMyksICIlIiksIHhsYWI9IlllYXIiLCB5bGFiPSJNZWRpYW4gVmFsdWUiKQpsaW5lcyhsb3VkbmVzcykKCiNTQVJJTUEKbG91ZG5lc3Muc2FyaW1hLm1vZGVsIDwtIGF1dG8uYXJpbWEobG91ZG5lc3MudHJhaW4pCmxvdWRuZXNzLnNhcmltYSA8LSBmb3JlY2FzdChsb3VkbmVzcy5zYXJpbWEubW9kZWwsIGg9blRlc3QpCmxvdWRuZXNzLnNhcmltYS5tYXBlID0gbWFwZShsb3VkbmVzcy5zYXJpbWEkbWVhbiwgbG91ZG5lc3MudGVzdCkKcGxvdChsb3VkbmVzcy5zYXJpbWEsIG1haW49cGFzdGUoImxvdWRuZXNzIiwgIlNBUklNQSIpLCBzdWI9cGFzdGUoIk1BUEU6Iiwgcm91bmQobG91ZG5lc3Muc2FyaW1hLm1hcGUqMTAwLCAzKSwgIiUiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKGxvdWRuZXNzKQoKCiNOZXVyYWwgTmV0d29yawpsb3VkbmVzcy50cmFpbi5ubiA8LSBlbG0obG91ZG5lc3MudHJhaW4pCmxvdWRuZXNzLm5uLmZvcmVjYXN0IDwtIGZvcmVjYXN0KGxvdWRuZXNzLnRyYWluLm5uLCBoPW5UZXN0KQpsb3VkbmVzcy5ubi5tYXBlID0gbWFwZShsb3VkbmVzcy5ubi5mb3JlY2FzdCRtZWFuLCBsb3VkbmVzcy50ZXN0KQpwbG90KGxvdWRuZXNzLCBtYWluPXBhc3RlKCJsb3VkbmVzcyIsICJOTiIpLCBzdWI9cGFzdGUoIk1BUEU6Iiwgcm91bmQobG91ZG5lc3Mubm4ubWFwZSoxMDAsIDMpLCAiJSIpLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIikKbGluZXModHMobG91ZG5lc3Mubm4uZm9yZWNhc3QkbWVhbiwgc3RhcnQ9MTkyMStuVHJhaW4pLCBjb2w9MikKYGBgCiMjIyMjIEluc2lnaHRzOgpIZXJlIHdlIHNlZSB0aGF0IHRoZSBiZXN0IG1ldGhvZCB0byBwcmVkaWN0IGZ1dHVyZSBsb3VkbmVzcyBtZWRpYW4gdmFsdWVzIGZvciB0aGUgb3ZlcmFsbCBkYXRhIHNldCBpcyB0aHJvdWdoIFNFUyBHaXZlbiB0aGF0IHRoaXMgYmVzdCBNQVBFIGlzIHJvdWdobHkgNSUsIHRoaXMgZmVhdHVyZSBjYW4gYmUgZmFpcmx5IHJlbGlhYmx5IGZvcmVjYXN0IGludG8gdGhlIGZ1dHVyZS4KICAKIyBMaW5lYXIgTW9kZWwgZm9yIE92ZXJhbGwgRmVhdHVyZSBNZWRpYW4tLT5Nb3N0IFBvcHVsYXIgU29uZ3MnIEZlYXR1cmUgTWVkaWFuCiMjIyBXZSB3aWxsIG9ubHkgY29uc2lkZXIgbW9kZWxzIHRoYXQgaGFkIGEgbG93IGVub3VnaCBNQVBFcyAoMTAlIGNob3NlbiBhcyBhIHRocmVzaG9sZCkgaW4gdGhlaXIgYmVzdCB0aW1lc2VyaWVzIGZvcmVjYXN0aW5nIG1vZGVsLgojIyMgSGVyZSBNQVBFIGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGFjdHVhbCBtZWRpYW4gZm9yIG1vc3QgcG9wdWxhciBzb25ncyBhbmQgdGhlIHByZWRpY3RlZCBtZWRpYW4uCgpgYGB7cn0KI0VuZXJneQpiZXN0X2VuZXJneSA9IHRzKGFzLm51bWVyaWMoYmVzdF9mZWF0dXJlX3F1YW50aWxlc1ssImVuZXJneSJdKSwgc3RhcnQ9MTkyMSwgZW5kPTIwMjApIApiZXN0X2VuZXJneS50cmFpbiA9IHN1YnNldChiZXN0X2VuZXJneSwgc3RhcnQgPSAxLCBlbmQgPSBuVHJhaW4pCmJlc3RfZW5lcmd5LnRlc3QgPSBzdWJzZXQoYmVzdF9lbmVyZ3ksIHN0YXJ0ID0gblRyYWluKzEsIGVuZCA9IG5UcmFpbituVGVzdCkKdHJhaW5fZGYgPSBkYXRhLmZyYW1lKGJlc3QgPSBiZXN0X2VuZXJneS50cmFpbiwgb3ZlcmFsbCA9IGVuZXJneS50cmFpbikKCmJlc3QgPSBiZXN0X2VuZXJneS50cmFpbgpvdmVyYWxsID0gZW5lcmd5LnRyYWluCgplbmVyZ3kubG0gPC0gbG0oYmVzdCB+IG92ZXJhbGwpCnRlc3RfZGYgPC0gZGF0YS5mcmFtZShvdmVyYWxsID0gZW5lcmd5LnRlc3QpCmJlc3RfZW5lcmd5LnRlc3QucHJlZGljdCA8LSBwcmVkaWN0KGVuZXJneS5sbSwgbmV3ZGF0YT10ZXN0X2RmLCBpbnRlcnZhbD0icHJlZGljdGlvbiIpCmJlc3RfZW5lcmd5X3Rlc3RfcHJlZGljdC5tYXBlIDwtIG1hcGUoYmVzdF9lbmVyZ3kudGVzdFsxOmxlbmd0aChiZXN0X2VuZXJneS50ZXN0KV0sIGJlc3RfZW5lcmd5LnRlc3QucHJlZGljdFssMV0pCnBsb3QoYmVzdF9lbmVyZ3kseGxhYj0iWWVhciIsIHlsYWI9IkVuZXJneSIsIG1haW49cGFzdGUoIkVuZXJneSBQb3B1bGFyaXR5IFByZWRpY3Rpb24iKSwgc3ViID0gcGFzdGUoIk1BUEU6ICIsIHJvdW5kKGJlc3RfZW5lcmd5X3Rlc3RfcHJlZGljdC5tYXBlKjEwMCwgMyksICIlIikpCmxpbmVzKHRzKGJlc3RfZW5lcmd5LnRlc3QucHJlZGljdFssMV0sIHN0YXJ0ID0gMTkyMStuVHJhaW4rMSwgZW5kID0gMjAyMCksIGNvbCA9IDIpCgojRHVyYXRpb24KYmVzdF9kdXJhdGlvbiA9IHRzKGFzLm51bWVyaWMoYmVzdF9mZWF0dXJlX3F1YW50aWxlc1ssImR1cmF0aW9uX21zIl0pLCBzdGFydD0xOTIxLCBlbmQ9MjAyMCkgCmJlc3RfZHVyYXRpb24udHJhaW4gPSBzdWJzZXQoYmVzdF9kdXJhdGlvbiwgc3RhcnQgPSAxLCBlbmQgPSBuVHJhaW4pCmJlc3RfZHVyYXRpb24udGVzdCA9IHN1YnNldChiZXN0X2R1cmF0aW9uLCBzdGFydCA9IG5UcmFpbisxLCBlbmQgPSBuVHJhaW4rblRlc3QpCnRyYWluX2RmID0gZGF0YS5mcmFtZShiZXN0ID0gYmVzdF9kdXJhdGlvbi50cmFpbiwgb3ZlcmFsbCA9IGR1cmF0aW9uLnRyYWluKQoKYmVzdCA9IGJlc3RfZHVyYXRpb24udHJhaW4Kb3ZlcmFsbCA9IGR1cmF0aW9uLnRyYWluCgpkdXJhdGlvbi5sbSA8LSBsbShiZXN0IH4gb3ZlcmFsbCkKdGVzdF9kZiA8LSBkYXRhLmZyYW1lKG92ZXJhbGwgPSBkdXJhdGlvbi50ZXN0KQpiZXN0X2R1cmF0aW9uLnRlc3QucHJlZGljdCA8LSBwcmVkaWN0KGR1cmF0aW9uLmxtLCBuZXdkYXRhPXRlc3RfZGYsIGludGVydmFsPSJwcmVkaWN0aW9uIikKYmVzdF9kdXJhdGlvbl90ZXN0LnByZWRpY3QubWFwZSA8LSBtYXBlKGJlc3RfZHVyYXRpb24udGVzdFsxOmxlbmd0aChiZXN0X2R1cmF0aW9uLnRlc3QpXSwgYmVzdF9kdXJhdGlvbi50ZXN0LnByZWRpY3RbLDFdKQpwbG90KGJlc3RfZHVyYXRpb24seGxhYj0iWWVhciIsIHlsYWI9ImR1cmF0aW9uIiwgbWFpbj1wYXN0ZSgiZHVyYXRpb24gUG9wdWxhcml0eSBQcmVkaWN0aW9uIiksIHN1YiA9IHBhc3RlKCJNQVBFOiAiLCByb3VuZChiZXN0X2R1cmF0aW9uX3Rlc3QucHJlZGljdC5tYXBlKjEwMCwgMyksICIlIikpCmxpbmVzKHRzKGJlc3RfZHVyYXRpb24udGVzdC5wcmVkaWN0WywxXSwgc3RhcnQgPSAxOTIxK25UcmFpbisxLCBlbmQgPSAyMDIwKSwgY29sID0gMikKCiNBY2NvdXN0aWNuZXNzCmJlc3RfYWNvdXN0aWNuZXNzID0gdHMoYXMubnVtZXJpYyhiZXN0X2ZlYXR1cmVfcXVhbnRpbGVzWywiYWNvdXN0aWNuZXNzIl0pLCBzdGFydD0xOTIxLCBlbmQ9MjAyMCkgCmJlc3RfYWNvdXN0aWNuZXNzLnRyYWluID0gc3Vic2V0KGJlc3RfYWNvdXN0aWNuZXNzLCBzdGFydCA9IDEsIGVuZCA9IG5UcmFpbikKYmVzdF9hY291c3RpY25lc3MudGVzdCA9IHN1YnNldChiZXN0X2Fjb3VzdGljbmVzcywgc3RhcnQgPSBuVHJhaW4rMSwgZW5kID0gblRyYWluK25UZXN0KQp0cmFpbl9kZiA9IGRhdGEuZnJhbWUoYmVzdCA9IGJlc3RfYWNvdXN0aWNuZXNzLnRyYWluLCBvdmVyYWxsID0gYWNvdXN0aWNuZXNzLnRyYWluKQoKYmVzdCA9IGJlc3RfYWNvdXN0aWNuZXNzLnRyYWluCm92ZXJhbGwgPSBhY291c3RpY25lc3MudHJhaW4KCmFjb3VzdGljbmVzcy5sbSA8LSBsbShiZXN0IH4gb3ZlcmFsbCkKdGVzdF9kZiA8LSBkYXRhLmZyYW1lKG92ZXJhbGwgPSBhY291c3RpY25lc3MudGVzdCkKYmVzdF9hY291c3RpY25lc3MudGVzdC5wcmVkaWN0IDwtIHByZWRpY3QoYWNvdXN0aWNuZXNzLmxtLCBuZXdkYXRhPXRlc3RfZGYsIGludGVydmFsPSJwcmVkaWN0aW9uIikKYmVzdF9hY291c3RpY25lc3NfdGVzdC5wcmVkaWN0Lm1hcGUgPC0gbWFwZShiZXN0X2Fjb3VzdGljbmVzcy50ZXN0WzE6bGVuZ3RoKGJlc3RfYWNvdXN0aWNuZXNzLnRlc3QpXSwgYmVzdF9hY291c3RpY25lc3MudGVzdC5wcmVkaWN0WywxXSkKcGxvdChiZXN0X2Fjb3VzdGljbmVzcyx4bGFiPSJZZWFyIiwgeWxhYj0iYWNvdXN0aWNuZXNzIiwgbWFpbj1wYXN0ZSgiYWNvdXN0aWNuZXNzIFBvcHVsYXJpdHkgUHJlZGljdGlvbiIpLCBzdWIgPSBwYXN0ZSgiTUFQRTogIiwgcm91bmQoYmVzdF9hY291c3RpY25lc3NfdGVzdC5wcmVkaWN0Lm1hcGUqMTAwLCAzKSwgIiUiKSkKbGluZXModHMoYmVzdF9hY291c3RpY25lc3MudGVzdC5wcmVkaWN0WywxXSwgc3RhcnQgPSAxOTIxK25UcmFpbisxLCBlbmQgPSAyMDIwKSwgY29sID0gMikKCiNWYWxlbmNlCmJlc3RfdmFsZW5jZSA9IHRzKGFzLm51bWVyaWMoYmVzdF9mZWF0dXJlX3F1YW50aWxlc1ssInZhbGVuY2UiXSksIHN0YXJ0PTE5MjEsIGVuZD0yMDIwKSAKYmVzdF92YWxlbmNlLnRyYWluID0gc3Vic2V0KGJlc3RfdmFsZW5jZSwgc3RhcnQgPSAxLCBlbmQgPSBuVHJhaW4pCmJlc3RfdmFsZW5jZS50ZXN0ID0gc3Vic2V0KGJlc3RfdmFsZW5jZSwgc3RhcnQgPSBuVHJhaW4rMSwgZW5kID0gblRyYWluK25UZXN0KQp0cmFpbl9kZiA9IGRhdGEuZnJhbWUoYmVzdCA9IGJlc3RfdmFsZW5jZS50cmFpbiwgb3ZlcmFsbCA9IHZhbGVuY2UudHJhaW4pCgpiZXN0ID0gYmVzdF92YWxlbmNlLnRyYWluCm92ZXJhbGwgPSB2YWxlbmNlLnRyYWluCgp2YWxlbmNlLmxtIDwtIGxtKGJlc3QgfiBvdmVyYWxsKQp0ZXN0X2RmIDwtIGRhdGEuZnJhbWUob3ZlcmFsbCA9IHZhbGVuY2UudGVzdCkKYmVzdF92YWxlbmNlLnRlc3QucHJlZGljdCA8LSBwcmVkaWN0KHZhbGVuY2UubG0sIG5ld2RhdGE9dGVzdF9kZiwgaW50ZXJ2YWw9InByZWRpY3Rpb24iKQpiZXN0X3ZhbGVuY2VfdGVzdC5wcmVkaWN0Lm1hcGUgPC0gbWFwZShiZXN0X3ZhbGVuY2UudGVzdFsxOmxlbmd0aChiZXN0X3ZhbGVuY2UudGVzdCldLCBiZXN0X3ZhbGVuY2UudGVzdC5wcmVkaWN0WywxXSkKcGxvdChiZXN0X3ZhbGVuY2UseGxhYj0iWWVhciIsIHlsYWI9IlZhbGVuY2UiLCBtYWluPXBhc3RlKCJWYWxlbmNlIFBvcHVsYXJpdHkgUHJlZGljdGlvbiIpLCBzdWIgPSBwYXN0ZSgiTUFQRTogIiwgcm91bmQoYmVzdF92YWxlbmNlX3Rlc3QucHJlZGljdC5tYXBlKjEwMCwgMyksICIlIikpCmxpbmVzKHRzKGJlc3RfdmFsZW5jZS50ZXN0LnByZWRpY3RbLDFdLCBzdGFydCA9IDE5MjErblRyYWluKzEsIGVuZCA9IDIwMjApLCBjb2wgPSAyKQoKI1RlbXBvCmJlc3RfdGVtcG8gPSB0cyhhcy5udW1lcmljKGJlc3RfZmVhdHVyZV9xdWFudGlsZXNbLCJ0ZW1wbyJdKSwgc3RhcnQ9MTkyMSwgZW5kPTIwMjApIApiZXN0X3RlbXBvLnRyYWluID0gc3Vic2V0KGJlc3RfdGVtcG8sIHN0YXJ0ID0gMSwgZW5kID0gblRyYWluKQpiZXN0X3RlbXBvLnRlc3QgPSBzdWJzZXQoYmVzdF90ZW1wbywgc3RhcnQgPSBuVHJhaW4rMSwgZW5kID0gblRyYWluK25UZXN0KQp0cmFpbl9kZiA9IGRhdGEuZnJhbWUoYmVzdCA9IGJlc3RfdGVtcG8udHJhaW4sIG92ZXJhbGwgPSB0ZW1wby50cmFpbikKCmJlc3QgPSBiZXN0X3RlbXBvLnRyYWluCm92ZXJhbGwgPSB0ZW1wby50cmFpbgoKdGVtcG8ubG0gPC0gbG0oYmVzdCB+IG92ZXJhbGwpCnRlc3RfZGYgPC0gZGF0YS5mcmFtZShvdmVyYWxsID0gdGVtcG8udGVzdCkKYmVzdF90ZW1wby50ZXN0LnByZWRpY3QgPC0gcHJlZGljdCh0ZW1wby5sbSwgbmV3ZGF0YT10ZXN0X2RmLCBpbnRlcnZhbD0icHJlZGljdGlvbiIpCmJlc3RfdGVtcG9fdGVzdC5wcmVkaWN0Lm1hcGUgPC0gbWFwZShiZXN0X3RlbXBvLnRlc3RbMTpsZW5ndGgoYmVzdF90ZW1wby50ZXN0KV0sIGJlc3RfdGVtcG8udGVzdC5wcmVkaWN0WywxXSkKcGxvdChiZXN0X3RlbXBvLHhsYWI9IlllYXIiLCB5bGFiPSJ0ZW1wbyIsIG1haW49cGFzdGUoInRlbXBvIFBvcHVsYXJpdHkgUHJlZGljdGlvbiIpLCBzdWIgPSBwYXN0ZSgiTUFQRTogIiwgcm91bmQoYmVzdF90ZW1wb190ZXN0LnByZWRpY3QubWFwZSoxMDAsIDMpLCAiJSIpKQpsaW5lcyh0cyhiZXN0X3RlbXBvLnRlc3QucHJlZGljdFssMV0sIHN0YXJ0ID0gMTkyMStuVHJhaW4rMSwgZW5kID0gMjAyMCksIGNvbCA9IDIpCgojTGl2ZW5lc3MKYmVzdF9saXZlbmVzcyA9IHRzKGFzLm51bWVyaWMoYmVzdF9mZWF0dXJlX3F1YW50aWxlc1ssImxpdmVuZXNzIl0pLCBzdGFydD0xOTIxLCBlbmQ9MjAyMCkgCmJlc3RfbGl2ZW5lc3MudHJhaW4gPSBzdWJzZXQoYmVzdF9saXZlbmVzcywgc3RhcnQgPSAxLCBlbmQgPSBuVHJhaW4pCmJlc3RfbGl2ZW5lc3MudGVzdCA9IHN1YnNldChiZXN0X2xpdmVuZXNzLCBzdGFydCA9IG5UcmFpbisxLCBlbmQgPSBuVHJhaW4rblRlc3QpCnRyYWluX2RmID0gZGF0YS5mcmFtZShiZXN0ID0gYmVzdF9saXZlbmVzcy50cmFpbiwgb3ZlcmFsbCA9IGxpdmVuZXNzLnRyYWluKQoKYmVzdCA9IGJlc3RfbGl2ZW5lc3MudHJhaW4Kb3ZlcmFsbCA9IGxpdmVuZXNzLnRyYWluCgpsaXZlbmVzcy5sbSA8LSBsbShiZXN0IH4gb3ZlcmFsbCkKdGVzdF9kZiA8LSBkYXRhLmZyYW1lKG92ZXJhbGwgPSBsaXZlbmVzcy50ZXN0KQpiZXN0X2xpdmVuZXNzLnRlc3QucHJlZGljdCA8LSBwcmVkaWN0KGxpdmVuZXNzLmxtLCBuZXdkYXRhPXRlc3RfZGYsIGludGVydmFsPSJwcmVkaWN0aW9uIikKYmVzdF9saXZlbmVzc190ZXN0LnByZWRpY3QubWFwZSA8LSBtYXBlKGJlc3RfbGl2ZW5lc3MudGVzdFsxOmxlbmd0aChiZXN0X2xpdmVuZXNzLnRlc3QpXSwgYmVzdF9saXZlbmVzcy50ZXN0LnByZWRpY3RbLDFdKQpwbG90KGJlc3RfbGl2ZW5lc3MseGxhYj0iWWVhciIsIHlsYWI9ImxpdmVuZXNzIiwgbWFpbj1wYXN0ZSgibGl2ZW5lc3MgUG9wdWxhcml0eSBQcmVkaWN0aW9uIiksIHN1YiA9IHBhc3RlKCJNQVBFOiAiLCByb3VuZChiZXN0X2xpdmVuZXNzX3Rlc3QucHJlZGljdC5tYXBlKjEwMCwgMyksICIlIikpCmxpbmVzKHRzKGJlc3RfbGl2ZW5lc3MudGVzdC5wcmVkaWN0WywxXSwgc3RhcnQgPSAxOTIxK25UcmFpbisxLCBlbmQgPSAyMDIwKSwgY29sID0gMikKCiNMb3VkbmVzcwpiZXN0X2xvdWRuZXNzID0gdHMoYXMubnVtZXJpYyhiZXN0X2ZlYXR1cmVfcXVhbnRpbGVzWywibG91ZG5lc3MiXSksIHN0YXJ0PTE5MjEsIGVuZD0yMDIwKSAKYmVzdF9sb3VkbmVzcy50cmFpbiA9IHN1YnNldChiZXN0X2xvdWRuZXNzLCBzdGFydCA9IDEsIGVuZCA9IG5UcmFpbikKYmVzdF9sb3VkbmVzcy50ZXN0ID0gc3Vic2V0KGJlc3RfbG91ZG5lc3MsIHN0YXJ0ID0gblRyYWluKzEsIGVuZCA9IG5UcmFpbituVGVzdCkKdHJhaW5fZGYgPSBkYXRhLmZyYW1lKGJlc3QgPSBiZXN0X2xvdWRuZXNzLnRyYWluLCBvdmVyYWxsID0gbG91ZG5lc3MudHJhaW4pCgpiZXN0ID0gYmVzdF9sb3VkbmVzcy50cmFpbgpvdmVyYWxsID0gbG91ZG5lc3MudHJhaW4KCmxvdWRuZXNzLmxtIDwtIGxtKGJlc3QgfiBvdmVyYWxsKQp0ZXN0X2RmIDwtIGRhdGEuZnJhbWUob3ZlcmFsbCA9IGxvdWRuZXNzLnRlc3QpCmJlc3RfbG91ZG5lc3MudGVzdC5wcmVkaWN0IDwtIHByZWRpY3QobG91ZG5lc3MubG0sIG5ld2RhdGE9dGVzdF9kZiwgaW50ZXJ2YWw9InByZWRpY3Rpb24iKQpiZXN0X2xvdWRuZXNzX3Rlc3QucHJlZGljdC5tYXBlIDwtIG1hcGUoYmVzdF9sb3VkbmVzcy50ZXN0WzE6bGVuZ3RoKGJlc3RfbG91ZG5lc3MudGVzdCldLCBiZXN0X2xvdWRuZXNzLnRlc3QucHJlZGljdFssMV0pCnBsb3QoYmVzdF9sb3VkbmVzcyx4bGFiPSJZZWFyIiwgeWxhYj0ibG91ZG5lc3MiLCBtYWluPXBhc3RlKCJsb3VkbmVzcyBQb3B1bGFyaXR5IFByZWRpY3Rpb24iKSwgc3ViID0gcGFzdGUoIk1BUEU6ICIsIHJvdW5kKGJlc3RfbG91ZG5lc3NfdGVzdC5wcmVkaWN0Lm1hcGUqMTAwLCAzKSwgIiUiKSkKbGluZXModHMoYmVzdF9sb3VkbmVzcy50ZXN0LnByZWRpY3RbLDFdLCBzdGFydCA9IDE5MjErblRyYWluKzEsIGVuZCA9IDIwMjApLCBjb2wgPSAyKQpgYGAKIyMjIyMgSW5zaWdodHM6CioqRW5lcmd5Kio6IEEgbG93IE1BUEUgYXJvdW5kIDQlIGluZGljYXRlcyB0aGF0IHdlIGNhbiB1c2UgdGhlIG92ZXJhbGwgdHJlbmQgdG8gaWRlbnRpZnkgdGhlIGVuZXJneSBvZiBwb3B1bGFyIHNvbmdzCioqRHVyYXRpb24qKjogQSBsb3cgTUFQRSBhcm91bmQgMSUgaW5kaWNhdGVzIHRoYXQgd2UgY2FuIHVzZSB0aGUgb3ZlcmFsbCB0cmVuZCB0byBpZGVudGlmeSB0aGUgZHVyYXRpb24gb2YgcG9wdWxhciBzb25ncwoqKkFjb3VzdGljbmVzcyoqOiBBIGhpZ2ggTUFQRSBhcm91bmQgMTYlIGluZGljYXRlcyB0aGF0IHdlIGNhbiBub3QgdXNlIHRoZSBvdmVyYWxsIHRyZW5kIHRvIGlkZW50aWZ5IHRoZSBhY291c3RpY25lc3Mgb2YgcG9wdWxhciBzb25ncy4gV2Ugd2lsbCBub3QgaW5jbHVkZSBwcmVkaWN0aW9ucyBmb3IgYWNvdXN0aWNuZXNzIG9mIHBvcHVsYXIgc29uZ3MuCioqVmFsZW5jZSoqOiBBIGxvdyBNQVBFIGFyb3VuZCA0LjYlIGluZGljYXRlcyB0aGF0IHdlIGNhbiB1c2UgdGhlIG92ZXJhbGwgdHJlbmQgdG8gaWRlbnRpZnkgdGhlIHZhbGVuY2Ugb2YgcG9wdWxhciBzb25ncwoqKlRlbXBvKio6IEEgbG93IE1BUEUgYXJvdW5kIDIlIGluZGljYXRlcyB0aGF0IHdlIGNhbiB1c2UgdGhlIG92ZXJhbGwgdHJlbmQgdG8gaWRlbnRpZnkgdGhlIHRlbXBvIG9mIHBvcHVsYXIgc29uZ3MKKipMaXZlbmVzcyoqOiBBIGxvdyBNQVBFIGFyb3VuZCA0LjMlIGluZGljYXRlcyB0aGF0IHdlIGNhbiB1c2UgdGhlIG92ZXJhbGwgdHJlbmQgdG8gaWRlbnRpZnkgdGhlIGxpdmVuZXNzIG9mIHBvcHVsYXIgc29uZ3MKKipMb3VkbmVzcyoqOiBBIGxvdyBNQVBFIGFyb3VuZCA1JSBpbmRpY2F0ZXMgdGhhdCB3ZSBjYW4gdXNlIHRoZSBvdmVyYWxsIHRyZW5kIHRvIGlkZW50aWZ5IHRoZSBsb3VkbmVzcyBvZiBwb3B1bGFyIHNvbmdzCgojIFByZWRpY3QgZmVhdHVyZXMgZm9yIHRoZSBvdmVyYWxsIG1hcmtldCB0cmVuZHMgZm9yIHRoZSBuZXh0IGZpdmUgeWVhcnMuCiMjIyBPbmx5IGluY2x1ZGluZyBmZWF0dXJlcyB3aG9zZSB0cmFpbmVkIGxpbmVhciBtb2RlbHMgaGFkIGEgTUFQRSBiZWxvdyAxMCUsIGFzIHRoZXNlIGFyZSB0aGUgZmVhdHVyZXMgd2hvc2UgbW9zdCBwb3B1bGFyIG1lZGlhbnMgd2lsbCBiZSBtb3N0IHJlbGlhYmx5IHByZWRpY3RlZCBieSB0aGVpciBmb3JlY2FzdCBvdmVyYWxsIHZhbHVlcy4KIyMjIFVzaW5nIHRoZSBiZXN0IHRpbWVzZXJpZXMgbWV0aG9kIHNlZW4gZm9yIGVhY2ggZmVhdHVyZS4KCiMjIEVuZXJneTogU0VTIE1vZGVsCgpgYGB7cn0KZW5lcmd5LnNlcyA8LSBzZXMoZW5lcmd5LCBoPW5UZXN0KQpwbG90KGVuZXJneS5zZXMsIG1haW49cGFzdGUoIkVuZXJneSIsICJTRVMiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKGVuZXJneSkKYGBgCgojIyBEdXJhdGlvbjogTk4gTW9kZWwKCmBgYHtyfQpkdXJhdGlvbi5ubiA8LSBlbG0oZHVyYXRpb24pCmR1cmF0aW9uLm5uLnByZWRpY3QgPC0gZm9yZWNhc3QoZHVyYXRpb24ubm4sIGg9blRlc3QpCnBsb3QoZHVyYXRpb24ubm4ucHJlZGljdCwgbWFpbj1wYXN0ZSgiRHVyYXRpb24iLCAiTk4iKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmBgYAoKIyMgVGVtcG86IFNFUyBNb2RlbCAKCmBgYHtyfQp0ZW1wby5zZXMgPC0gc2VzKHRlbXBvLCBoPW5UZXN0KQpwbG90KHRlbXBvLnNlcywgbWFpbj1wYXN0ZSgiVGVtcG8iLCAiU0VTIiksIHhsYWI9IlllYXIiLCB5bGFiPSJNZWRpYW4gVmFsdWUiKQpsaW5lcyh0ZW1wbykKYGBgCgojIyBWYWxlbmNlOiBTQVJJTUEgTW9kZWwKCmBgYHtyfQp2YWxlbmNlLnNhcmltYSA8LSBhdXRvLmFyaW1hKHZhbGVuY2UpCnZhbGVuY2Uuc2FyaW1hLnByZWRpY3QgPC0gZm9yZWNhc3QodmFsZW5jZS5zYXJpbWEsIGg9blRlc3QpCnBsb3QodmFsZW5jZS5zYXJpbWEucHJlZGljdCwgbWFpbj1wYXN0ZSgiVmFsZW5jZSIsICJTQVJJTUEiKSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIpCmxpbmVzKHZhbGVuY2UpCmBgYAoKIyMgTGl2ZW5lc3M6IFNBUklNQSBNb2RlbAoKYGBge3J9CmxpdmVuZXNzLnNhcmltYSA8LSBhdXRvLmFyaW1hKGxpdmVuZXNzKQpsaXZlbmVzcy5zYXJpbWEucHJlZGljdCA8LSBmb3JlY2FzdChsaXZlbmVzcy5zYXJpbWEsIGg9blRlc3QpCnBsb3QobGl2ZW5lc3Muc2FyaW1hLnByZWRpY3QsIG1haW49cGFzdGUoImxpdmVuZXNzIiwgIlNBUklNQSIpLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIikKbGluZXMobGl2ZW5lc3MpCmBgYAoKIyMgTG91ZG5lc3M6IFNFUyBNb2RlbCAKCmBgYHtyfQpsb3VkbmVzcy5zZXMgPC0gc2VzKGxvdWRuZXNzLCBoPW5UZXN0KQpwbG90KGxvdWRuZXNzLnNlcywgbWFpbj1wYXN0ZSgibG91ZG5lc3MiLCAiU0VTIiksIHhsYWI9IlllYXIiLCB5bGFiPSJNZWRpYW4gVmFsdWUiKQpsaW5lcyhsb3VkbmVzcykKYGBgCgoKCgoKIyBOb3cgcHJlZGljdGluZyB0aGUgbWVkaWFuIHZhbHVlcyBmb3IgdGhlICptb3N0IHBvcHVsYXIgc29uZ3MqIGZvciB0aGlzIHNldCBvZiBmZWF0dXJlcy4KIyMjIFRoZSBmb3JlY2FzdCBvdmVyYWxsIG1lZGlhbiB2YWx1ZXMgYW5kIGxpbmVhciBtb2RlbCBwcmVkaWN0aW5nIHRoZSBtb3N0IHBvcHVsYXIgbWVkaWFuIHZhbHVlcyBmb3IgZWFjaCBmZWF0dXJlIGdpdmVuIG92ZXJhbGwgbWVkaWFuIHZhbHVlIHdpbGwgYmUgdXNlZCB0byBwcmVkaWN0IHRoZSBmdXR1cmUgbWVkaWFuIHZhbHVlcyBmb3IgcG9wdWxhciBzb25ncyBmb3IgZWFjaCBmZWF0dXJlLgoKIyMgRW5lcmd5CgpgYGB7cn0KYmVzdCA9IGJlc3RfZW5lcmd5Cm92ZXJhbGwgPSBlbmVyZ3kKCgplbmVyZ3kubG0gPC0gbG0oYmVzdCB+IG92ZXJhbGwpCnByZWRpY3RfZGYgPC0gZGF0YS5mcmFtZShvdmVyYWxsID0gZW5lcmd5LnNlcyRtZWFuKQplbmVyZ3kucHJlZGljdCA8LSBwcmVkaWN0KGVuZXJneS5sbSwgbmV3ZGF0YT1wcmVkaWN0X2RmLCBpbnRlcnZhbD0icHJlZGljdGlvbiIpCgpzbWFsbGVzdCA9IG1pbihtaW4oYmVzdCksIG1pbihvdmVyYWxsKSkKYmlnZ2VzdCA9IG1heChtYXgoYmVzdCksIG1heChvdmVyYWxsKSkKcGxvdChlbmVyZ3ksIHhsYWI9IlllYXIiLCB5bGFiPSJNZWRpYW4gVmFsdWUiLCB5bGltPWMoc21hbGxlc3QsIGJpZ2dlc3QpLCBtYWluPSJNb3N0IFBvcHVsYXIgU29uZydzIEVuZXJneSBGZWF0dXJlIFByZWRpY3Rpb24iLCBzdWI9cGFzdGUoIlByb2plY3RlZCBtZWRpYW4gZmVhdHVyZSB2YWx1ZSBmb3IgbW9zdCBwb3B1bGFyIHNvbmdzOiIsIHBhc3RlKHJvdW5kKGVuZXJneS5zZXMkbWVhbiwgMyksIGNvbGxhcHNlPSIsIikgKSkKbGluZXMoYmVzdF9lbmVyZ3ksIGNvbCA9IDIpCmxpbmVzKHRzKGVuZXJneS5wcmVkaWN0WywxXSwgc3RhcnQ9MjAyMCsxLCBlbmQ9MjAyMCtuVGVzdCksIGNvbCA9IDMpCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCBsdHk9MSwgY29sPWMoMSwyLDMpLCBsZWdlbmQ9YygiT3ZlcmFsbCIsICJNb3N0IFBvcHVsYXIiLCAiTW9zdCBQb3B1bGFyIFByb2plY3Rpb24iKSkKYGBgCgoKIyMgRHVyYXRpb24KCmBgYHtyfQpiZXN0ID0gYmVzdF9kdXJhdGlvbgpvdmVyYWxsID0gZHVyYXRpb24KCmR1cmF0aW9uLmxtIDwtIGxtKGJlc3QgfiBvdmVyYWxsKQpwcmVkaWN0X2RmIDwtIGRhdGEuZnJhbWUob3ZlcmFsbCA9IGR1cmF0aW9uLm5uLnByZWRpY3QkbWVhbikKZHVyYXRpb24ucHJlZGljdCA8LSBwcmVkaWN0KGR1cmF0aW9uLmxtLCBuZXdkYXRhPXByZWRpY3RfZGYsIGludGVydmFsPSJwcmVkaWN0aW9uIikKCnNtYWxsZXN0ID0gbWluKG1pbihiZXN0KSwgbWluKG92ZXJhbGwpKQpiaWdnZXN0ID0gbWF4KG1heChiZXN0KSwgbWF4KG92ZXJhbGwpKQpwbG90KGR1cmF0aW9uLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIiwgeWxpbT1jKHNtYWxsZXN0LCBiaWdnZXN0KSwgbWFpbj0iTW9zdCBQb3B1bGFyIFNvbmcncyBEdXJhdGlvbiBGZWF0dXJlIFByZWRpY3Rpb24iLCBzdWI9cGFzdGUoIlByb2plY3RlZCBtZWRpYW4gZmVhdHVyZSB2YWx1ZSBmb3IgbW9zdCBwb3B1bGFyIHNvbmdzOiIsIHBhc3RlKHJvdW5kKGR1cmF0aW9uLm5uLnByZWRpY3QkbWVhbiksIGNvbGxhcHNlPSIsIikgKSkKbGluZXMoYmVzdF9kdXJhdGlvbiwgY29sID0gMikKbGluZXModHMoZHVyYXRpb24ucHJlZGljdFssMV0sIHN0YXJ0PTIwMjArMSwgZW5kPTIwMjArblRlc3QpLCBjb2wgPSAzKQpsZWdlbmQoInRvcHJpZ2h0IiwgbHR5PTEsIGNvbD1jKDEsMiwzKSwgbGVnZW5kPWMoIk92ZXJhbGwiLCAiTW9zdCBQb3B1bGFyIiwgIk1vc3QgUG9wdWxhciBQcm9qZWN0aW9uIikpCmBgYAoKCiMjIFRlbXBvCgpgYGB7cn0KYmVzdCA9IGJlc3RfdGVtcG8Kb3ZlcmFsbCA9IHRlbXBvCgp0ZW1wby5sbSA8LSBsbShiZXN0IH4gb3ZlcmFsbCkKcHJlZGljdF9kZiA8LSBkYXRhLmZyYW1lKG92ZXJhbGwgPSB0ZW1wby5zZXMkbWVhbikKdGVtcG8ucHJlZGljdCA8LSBwcmVkaWN0KHRlbXBvLmxtLCBuZXdkYXRhPXByZWRpY3RfZGYsIGludGVydmFsPSJwcmVkaWN0aW9uIikKCgpzbWFsbGVzdCA9IG1pbihtaW4oYmVzdCksIG1pbihvdmVyYWxsKSkKYmlnZ2VzdCA9IG1heChtYXgoYmVzdCksIG1heChvdmVyYWxsKSkKcGxvdCh0ZW1wbywgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIsIHlsaW09YyhzbWFsbGVzdCwgYmlnZ2VzdCksIG1haW49Ik1vc3QgUG9wdWxhciBTb25nJ3MgVGVtcG8gRmVhdHVyZSBQcmVkaWN0aW9uIiwgc3ViPXBhc3RlKCJQcm9qZWN0ZWQgbWVkaWFuIGZlYXR1cmUgdmFsdWUgZm9yIG1vc3QgcG9wdWxhciBzb25nczoiLCBwYXN0ZShyb3VuZCh0ZW1wby5zZXMkbWVhbiksIGNvbGxhcHNlPSIsIikgKSkKbGluZXMoYmVzdF90ZW1wbywgY29sID0gMikKbGluZXModHModGVtcG8ucHJlZGljdFssMV0sIHN0YXJ0PTIwMjArMSwgZW5kPTIwMjArblRlc3QpLCBjb2wgPSAzKQpsZWdlbmQoImJvdHRvbXJpZ2h0IiwgbHR5PTEsIGNvbD1jKDEsMiwzKSwgbGVnZW5kPWMoIk92ZXJhbGwiLCAiTW9zdCBQb3B1bGFyIiwgIk1vc3QgUG9wdWxhciBQcm9qZWN0aW9uIikpCmBgYAoKCiMjIFZhbGVuY2UKCmBgYHtyfQpiZXN0ID0gYmVzdF92YWxlbmNlCm92ZXJhbGwgPSB2YWxlbmNlCgp2YWxlbmNlLmxtIDwtIGxtKGJlc3QgfiBvdmVyYWxsKQpwcmVkaWN0X2RmIDwtIGRhdGEuZnJhbWUob3ZlcmFsbCA9IHZhbGVuY2Uuc2FyaW1hLnByZWRpY3QkbWVhbikKdmFsZW5jZS5wcmVkaWN0IDwtIHByZWRpY3QodmFsZW5jZS5sbSwgbmV3ZGF0YT1wcmVkaWN0X2RmLCBpbnRlcnZhbD0icHJlZGljdGlvbiIpCgoKc21hbGxlc3QgPSBtaW4obWluKGJlc3QpLCBtaW4ob3ZlcmFsbCkpCmJpZ2dlc3QgPSBtYXgobWF4KGJlc3QpLCBtYXgob3ZlcmFsbCkpCnBsb3QodmFsZW5jZSwgeGxhYj0iWWVhciIsIHlsYWI9Ik1lZGlhbiBWYWx1ZSIsIHlsaW09YyhzbWFsbGVzdCwgYmlnZ2VzdCksIG1haW49Ik1vc3QgUG9wdWxhciBTb25nJ3MgdmFsZW5jZSBGZWF0dXJlIFByZWRpY3Rpb24iLCBzdWI9cGFzdGUoIlByb2plY3RlZCBtZWRpYW4gZmVhdHVyZSB2YWx1ZSBmb3IgbW9zdCBwb3B1bGFyIHNvbmdzOiIsIHBhc3RlKHJvdW5kKHZhbGVuY2Uuc2FyaW1hLnByZWRpY3QkbWVhbiwzKSwgY29sbGFwc2U9IiwiKSApKQpsaW5lcyhiZXN0X3ZhbGVuY2UsIGNvbCA9IDIpCmxpbmVzKHRzKHZhbGVuY2UucHJlZGljdFssMV0sIHN0YXJ0PTIwMjArMSwgZW5kPTIwMjArblRlc3QpLCBjb2wgPSAzKQpsZWdlbmQoImJvdHRvbXJpZ2h0IiwgbHR5PTEsIGNvbD1jKDEsMiwzKSwgbGVnZW5kPWMoIk92ZXJhbGwiLCAiTW9zdCBQb3B1bGFyIiwgIk1vc3QgUG9wdWxhciBQcm9qZWN0aW9uIikpCmBgYAoKCiMjIExpdmVuZXNzCgpgYGB7cn0KYmVzdCA9IGJlc3RfbGl2ZW5lc3MKb3ZlcmFsbCA9IGxpdmVuZXNzCgpsaXZlbmVzcy5sbSA8LSBsbShiZXN0IH4gb3ZlcmFsbCkKcHJlZGljdF9kZiA8LSBkYXRhLmZyYW1lKG92ZXJhbGwgPSBsaXZlbmVzcy5zYXJpbWEucHJlZGljdCRtZWFuKQpsaXZlbmVzcy5wcmVkaWN0IDwtIHByZWRpY3QobGl2ZW5lc3MubG0sIG5ld2RhdGE9cHJlZGljdF9kZiwgaW50ZXJ2YWw9InByZWRpY3Rpb24iKQoKc21hbGxlc3QgPSBtaW4obWluKGJlc3QpLCBtaW4ob3ZlcmFsbCkpCmJpZ2dlc3QgPSBtYXgobWF4KGJlc3QpLCBtYXgob3ZlcmFsbCkpCnBsb3QobGl2ZW5lc3MsIHhsYWI9IlllYXIiLCB5bGFiPSJNZWRpYW4gVmFsdWUiLCB5bGltPWMoc21hbGxlc3QsIGJpZ2dlc3QpLCBtYWluPSJNb3N0IFBvcHVsYXIgU29uZydzIExpdmVuZXNzIEZlYXR1cmUgUHJlZGljdGlvbiIsIHN1Yj1wYXN0ZSgiUHJvamVjdGVkIG1lZGlhbiBmZWF0dXJlIHZhbHVlIGZvciBtb3N0IHBvcHVsYXIgc29uZ3M6IiwgcGFzdGUocm91bmQobGl2ZW5lc3Muc2FyaW1hLnByZWRpY3QkbWVhbiwzKSwgY29sbGFwc2U9IiwiKSApKQpsaW5lcyhiZXN0X2xpdmVuZXNzLCBjb2wgPSAyKQpsaW5lcyh0cyhsaXZlbmVzcy5wcmVkaWN0WywxXSwgc3RhcnQ9MjAyMCsxLCBlbmQ9MjAyMCtuVGVzdCksIGNvbCA9IDMpCmxlZ2VuZCgidG9wcmlnaHQiLCBsdHk9MSwgY29sPWMoMSwyLDMpLCBsZWdlbmQ9YygiT3ZlcmFsbCIsICJNb3N0IFBvcHVsYXIiLCAiTW9zdCBQb3B1bGFyIFByb2plY3Rpb24iKSkKYGBgCgoKCiMjIExvdWRuZXNzCgpgYGB7cn0KYmVzdCA9IGJlc3RfbG91ZG5lc3MKb3ZlcmFsbCA9IGxvdWRuZXNzCgpsb3VkbmVzcy5sbSA8LSBsbShiZXN0IH4gb3ZlcmFsbCkKcHJlZGljdF9kZiA8LSBkYXRhLmZyYW1lKG92ZXJhbGwgPSBsb3VkbmVzcy5zZXMkbWVhbikKbG91ZG5lc3MucHJlZGljdCA8LSBwcmVkaWN0KGxvdWRuZXNzLmxtLCBuZXdkYXRhPXByZWRpY3RfZGYsIGludGVydmFsPSJwcmVkaWN0aW9uIikKCnNtYWxsZXN0ID0gbWluKG1pbihiZXN0KSwgbWluKG92ZXJhbGwpKQpiaWdnZXN0ID0gbWF4KG1heChiZXN0KSwgbWF4KG92ZXJhbGwpKQpwbG90KGxvdWRuZXNzLCB4bGFiPSJZZWFyIiwgeWxhYj0iTWVkaWFuIFZhbHVlIiwgeWxpbT1jKHNtYWxsZXN0LCBiaWdnZXN0KSwgbWFpbj0iTW9zdCBQb3B1bGFyIFNvbmcncyBMb3VkbmVzcyBGZWF0dXJlIFByZWRpY3Rpb24iLCBzdWI9cGFzdGUoIlByb2plY3RlZCBtZWRpYW4gZmVhdHVyZSB2YWx1ZSBmb3IgbW9zdCBwb3B1bGFyIHNvbmdzOiIsIHBhc3RlKHJvdW5kKGxvdWRuZXNzLnNlcyRtZWFuLDEpLCBjb2xsYXBzZT0iLCIpICkpCmxpbmVzKGJlc3RfbG91ZG5lc3MsIGNvbCA9IDIpCmxpbmVzKHRzKGxvdWRuZXNzLnByZWRpY3RbLDFdLCBzdGFydD0yMDIwKzEsIGVuZD0yMDIwK25UZXN0KSwgY29sID0gMykKbGVnZW5kKCJib3R0b21yaWdodCIsIGx0eT0xLCBjb2w9YygxLDIsMyksIGxlZ2VuZD1jKCJPdmVyYWxsIiwgIk1vc3QgUG9wdWxhciIsICJNb3N0IFBvcHVsYXIgUHJvamVjdGlvbiIpKQpgYGAKIyMjIEltcGxpY2F0aW9uczoKVXNpbmcgdGhlc2UgdmFsdWVzIGFib3ZlIGZvciB0aGUgcHJlZGljdGVkIG1lZGlhbiB2YWx1ZSBmb3IgdGhlIG1vc3QgcG9wdWxhciBzb25ncywgZm9yIGVhY2ggZmVhdHVyZSwgbXVzaWMgY3VyYXRvcnMgYW5kIHJlY29yZCBsYWJlbHMgY2FuIHByZWRpY3Qgd2hpY2ggInNvdW5kcyIgd2lsbCBiZSBtb3N0IHBvcHVsYXIgaW4gdGhlIGZ1dHVyZS4gVGhpcyBpbmZvcm1hdGlvbiBjYW4gdGhlbiBiZSB1c2VkIGZvciBmdXR1cmUgZGVjaXNpb24gbWFraW5nIHdpdGggcmVzcGVjdCB0byB3aGljaCBhcnRpc3RzIHRvIHNpZ24gYW5kIHdoaWNoIHNvdW5kcyB0byBwdXNoLg==